Java printf 格式化输出
格式化输出是 Java 编程中的一项关键技能,它允许你以清晰、易读且专业的方式展示数据。printf 方法(以及相关的格式化功能)让你能够精确控制数字、日期、字符串和其他数据类型的显示方式。
本章将深入探讨 printf 的细节,为你提供为各种应用程序创建精美输出的工具。我们将基于上一章关于控制台打印的知识,并为后续章节中将数据写入文件做好准备。
1. 理解 printf
printf 方法继承自 C 语言,为 Java 提供了一种强大的格式化输出方式。它允许你在字符串中嵌入格式说明符 (Format Specifiers),这些说明符随后会被相应的参数替换。
通用语法如下:
System.out.printf(格式字符串, 参数1, 参数2, ...);- 格式字符串 (formatString):包含字面文本和格式说明符的字符串。
参数1, 参数2, ...:将被格式化并插入到格式字符串中的参数。参数的数量和类型必须与格式说明符相匹配。
如果你熟悉 println 方法,你会发现 printf 提供了更多的控制权。你不再是简单地将值拼接成字符串,而是精确指定输出的样式。
2. 格式说明符 (Format Specifiers)
格式说明符以百分号 (%) 开始,以指示参数数据类型的转换字符结束。以下是一些常用的转换字符:
| 转换字符 | 数据类型 | 描述 |
|---|---|---|
%d | int, byte, short, long | 将整数格式化为十进制数字。 |
| %f | float, double | 将浮点数格式化为十进制数字。 |
%s | String | 格式化字符串。 |
%c | char | 格式化字符。 |
%b | boolean | 将布尔值格式化为 "true" 或 "false"。 |
%n | (无) | 插入特定于平台的换行符。为了跨平台兼容性,通常建议使用 %n 而非 \n。 |
%% | (无) | 输出一个字面意义上的百分号 (%)。 |
示例:
int quantity = 10;
double price = 2.50;
String item = "苹果";
System.out.printf("我们有 %d 个 %s,每个售价为 $%.2f。%n", quantity, item, price);
// 输出: 我们有 10 个 苹果,每个售价为 $2.50。在这个例子中:
%d被quantity的值 (10) 替换。%s被item的值 ("苹果") 替换。%.2f被price的值 (2.50) 替换,并格式化为两位小数。%n插入一个换行符。
3. 标志、宽度与精度
格式说明符可以包含标志、宽度和精度修饰符,以进一步自定义输出。格式说明符的完整语法为:
%[标志][宽度][.精度]转换字符3.1 标志 (Flags)
用于修改输出格式。常用标志包括:
-(左对齐):在指定的宽度内左对齐输出。+(包含符号):始终为数值包含正负号(+或-)。0(零填充):用前导零填充输出以达到指定宽度。,(分组分隔符):为数字使用特定于语言环境的分组分隔符(例如:美国用逗号,欧洲用点)。- 空格:在没有
+标志的正数前添加一个空格。
3.2 宽度 (Width)
指定输出的最小字符数。如果值的长度小于宽度,则会用空格(或在使用 0 标志时用零)填充。
3.3 精度 (Precision)
指定浮点数小数点后的位数,或字符串输出的最大字符数。
代码示例:
int number = 123;
double value = 1234.5678;
String text = "Hello";
System.out.printf("宽度为 6 的数字: %6d%n", number); // 输出: " 123"
System.out.printf("零填充数字: %06d%n", number); // 输出: "000123"
System.out.printf("精度为 2 的数值: %.2f%n", value); // 输出: "1234.57" (注意四舍五入)
System.out.printf("带分组分隔符的数值: %,f%n", value); // 输出: "1,234.567800" (取决于地区)
System.out.printf("左对齐文本: %-10s!%n", text); // 输出: "Hello !"4. 日期与时间格式化
printf 还支持使用特殊的转换字符格式化日期和时间值。这些说明符以 %t 开头。
| 转换字符 | 描述 | 示例 (基于当前日期) |
|---|---|---|
%tD | 格式化为 MM/DD/YY | 03/15/26 |
%tF | 格式化为 YYYY-MM-DD | 2026-03-15 |
%tT | 格式化为 HH:MM:SS (24小时制) | 14:30:45 |
%tr | 格式化为带 AM/PM 的时间 | 02:30:45 PM |
%tA | 星期几的全称 | 星期五 (取决于语言环境) |
%tB | 月份的全称 | 三月 |
%tY | 四位年份 | 2026 |
示例:
import java.util.Date;
public class DateFormatExample {
public static void main(String[] args) {
Date today = new Date();
// 使用 < 标志引用前一个参数
System.out.printf("今天是: %tA, %tB %td, %tY%n", today, today, today, today);
// 输出: 今天是: 星期五, 三月 15, 2026
System.out.printf("当前时间: %tr%n", today);
}
}技巧: 如果你在同一个格式字符串中多次使用同一个日期对象,可以使用 1$ 这种形式或 < 标志来避免重复编写参数。System.out.printf("%1$tA, %1$tB %1$td, %1$tY%n", today); 这里的 1$ 表示引用第一个参数。
5. 参数索引 (Argument Index)
你可以通过参数索引明确指定参数的使用顺序。参数索引是一个整数后跟一个 $ 符号。例如,%2$d 指向第二个参数,%3$s 指向第三个参数。
String firstName = "张";
String lastName = "三";
// 输出: 三, 张
System.out.printf("%2$s, %1$s%n", firstName, lastName);6. 实际应用案例
6.1 案例 1:格式化表格输出
展示带有价格和数量的产品列表。
public class ProductTable {
public static void main(String[] args) {
String[] products = {"笔记本电脑", "鼠标", "键盘", "显示器"};
double[] prices = {1200.00, 25.50, 75.00, 300.75};
int[] quantities = {5, 20, 10, 7};
System.out.printf("%-12s %8s %8s%n", "产品名称", "价格", "数量");
System.out.println("----------------------------------");
for (int i = 0; i < products.length; i++) {
System.out.printf("%-12s %8.2f %8d%n", products[i], prices[i], quantities[i]);
}
}
}6.2 案例 2:带本地化设置的货币格式化
使用 java.util.Locale 根据不同地区的标准格式化金额。
import java.util.Locale;
public class CurrencyFormatting {
public static void main(String[] args) {
double amount = 1234.56;
// 美国美元格式
System.out.printf(Locale.US, "美国: $%,.2f%n", amount);
// 德国欧元格式
System.out.printf(Locale.GERMANY, "德国: %,.2f €%n", amount);
}
}