Java字符串格式化Formatter和printf()的使用详解
作者:面朝大海,春不暖,花不开
在 Java 编程中,字符串格式化是一项基本且重要的技能。它允许开发者以特定的方式将各种类型的数据(如数字、日期、字符串等)转换为字符串,以便于显示、存储或传输。
Java 提供了多种方法来实现字符串格式化,其中最常用的是 String.format()
、Java 15 引入的 string.formatted()
实例方法,以及 PrintStream
和 PrintWriter
类中的 printf()
方法。
这些方法都依赖于 java.util.Formatter
类,该类使用类似于 C 语言 printf()
函数的格式代码。
字符串格式化的方法
Java 提供了三种主要的字符串格式化方法,每种方法都有其特定的使用场景:
1.String.format()
这是一个静态方法,用于创建一个格式化的字符串。它接受一个格式字符串和一系列参数,返回一个格式化后的字符串。适用于需要将格式化结果存储为字符串的场景。
示例:
String str = String.format("Hello %s, today is %tF%n", "World", LocalDate.now()); System.out.println(str);
输出示例:
Hello World, today is 2025-04-27
2.string.formatted()
从 Java 15 开始,字符串实例提供了一个 formatted()
方法,可以直接对字符串进行格式化。其功能与 String.format()
类似,但语法更简洁,适合需要快速格式化的场景。
示例:
String str = "Hello %s, today is %tF%n".formatted("World", LocalDate.now()); System.out.println(str);
输出示例:
Hello World, today is 2025-04-27
3.printf()
PrintStream
和 PrintWriter
类提供了 printf()
方法,可以直接将格式化的字符串输出到流中(如控制台或文件)。它适合需要立即输出的场景。
示例:
System.out.printf("Hello %s, today is %tF%n", "World", LocalDate.now());
输出示例:
Hello World, today is 2025-04-27
格式字符串的结构
格式字符串由普通字符和格式代码组成。普通字符按原样输出,而格式代码以 %
开头,用于指定如何格式化参数。格式代码的完整结构如下:
% [argument_index$] [flags] [width] [.precision] conversion
- argument_index$:可选,指定要格式化的参数索引(从 1 开始)。例如,
%1$s
表示第一个参数作为字符串。 - flags:可选,控制输出格式,如
-
表示左对齐,0
表示用 0 填充。 - width:可选,指定字段的最小宽度。
- .precision:可选,对于浮点数,指定小数点后位数;对于字符串,指定最大字符数。
- conversion:必须,指定数据类型,如
d
(十进制整数)、f
(浮点数)、s
(字符串)等。
例如,%04d
表示将整数格式化为至少 4 位,不足时前面补 0;%4.2f
表示浮点数总宽度至少 4 位,小数点后 2 位。
常用格式代码
以下是 java.util.Formatter
类支持的一些常用格式代码:
格式代码 | 含义 |
---|---|
%b | 布尔值(true 或 false) |
%c | 字符 |
%d | 十进制整数(无小数点) |
%f | 浮点数(带小数部分) |
%s | 字符串(通用格式) |
%t | 日期/时间(需后跟具体代码) |
%n | 平台相关的换行符 |
%% | 字面上的 % 字符 |
对于某些代码(如 %b
、%c
、%s
),使用大写形式(如 %S
)会将结果转换为大写。
日期和时间格式化
日期和时间格式化使用 %t
前缀,后跟一个字符来指定具体格式。
以下是一些常用的日期/时间格式代码:
格式代码 | 含义 |
---|---|
%tA | 星期几的完整名称(如“星期日”) |
%ta | 星期几的缩写名称(如“周日”) |
%tB | 月份的完整名称(如“一月”) |
%tb | 月份的缩写名称(如“一月”) |
%td | 月份中的天(两位数,如“01”) |
%tY | 年份(至少四位,如“2025”) |
%tF | ISO 8601 日期格式(YYYY-MM-DD) |
日期格式化通常与 LocalDate
、Date
或 Calendar
等对象一起使用。
需要注意的是,当对同一日期对象格式化多个字段时,必须为每个格式代码指定参数索引(如 %1$tY
)。
代码示例
以下是一些实际应用中的格式化示例,涵盖数字、字符串和日期。
1. 格式化数字
System.out.printf("%04d - the year of %f%n", 1956, Math.PI);
- 输出:
1956 - the year of 3.141593
- 说明:
%04d
确保年份显示为 4 位,前面补 0;%f
显示浮点数Math.PI
的完整值。
2. 控制浮点数精度
System.out.printf("PI is approximately %4.2f%n", Math.PI);
- 输出:
PI is approximately 3.14
- 说明:
%4.2f
指定浮点数总宽度至少 4 位,小数点后保留 2 位。
3. 格式化日期
LocalDate today = LocalDate.now(); System.out.printf("Today is %1$tB %1$td, %1$tY%n", today);
- 输出示例:
Today is April 27, 2025
- 说明:
%1$tB
显示月份名称,%1$td
显示日期,%1$tY
显示年份,1$
确保使用同一个LocalDate
对象。
4. 使用参数索引重复格式化
System.out.printf("%1$tY-%1$tm-%1$td%n", LocalDate.now());
- 输出示例:
2025-04-27
- 说明:通过
1$
指定使用第一个参数(LocalDate.now()
),分别提取年、月、日。
5. 写入文件
try (Formatter formatter = new Formatter("output.txt")) { formatter.format("Price: $%5.2f%n", 27.99); }
说明:将格式化结果写入文件 output.txt
,内容为 Price: $27.99
。
最佳实践和注意事项
- 安全性:避免使用用户提供的格式字符串,因为格式字符串可能被恶意构造,导致安全漏洞。例如,攻击者可能利用格式代码访问不应访问的数据。始终对用户输入进行验证和清理。
- 国际化:在多语言应用中,直接使用日期格式代码(如
%tB
)可能不适合所有地区,因为不同语言对日期的显示顺序和格式有不同要求。建议使用java.time.format.DateTimeFormatter
来处理国际化日期格式化。 - 平台无关性:使用
%n
作为换行符,而不是硬编码\n
,因为%n
会根据运行平台自动选择正确的换行符。 - 性能:对于高性能场景,避免频繁创建
Formatter
对象。可以复用Formatter
实例或直接使用String.format()
和printf()
。
关于 StringTemplate 的说明
Java 21 和 22 引入了 StringTemplate
作为预览功能,旨在提供更简洁的字符串插值方式,例如 STR."Hello \{name}"
。然而,由于设计上的问题,该功能在 Java 23 中被撤回。根据 Java StringTemplate Discussion,开发团队正在探索更安全和优雅的实现方案,但目前尚无明确的时间表。
总结
Java 的字符串格式化工具通过 Formatter
类及其相关方法,为开发者提供了强大的数据格式化能力。无论是格式化数字、字符串还是日期,String.format()
、string.formatted()
和 printf()
都能满足各种需求。通过掌握格式代码的结构和用法,开发者可以编写更清晰、更高效的代码。然而,在使用时需注意安全性和国际化问题,以确保代码的健壮性和可移植性。
格式代码种类繁多,本文仅介绍了最常用的部分。欲了解完整列表,请参阅 Java Formatter Documentation。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。