Java格式化输出printf()解读
作者:RiskAI
本文通过实例详细介绍Java格式化输出 System.out.printf() 方法的使用、参数的含义、格式转换符使用时的注意事项。
1. printf API
// 使用指定的格式字符串和参数将格式化字符串写入入到输出流 public PrintStream printf(String format, Object ... args) // 基于本地化环境使用指定的格式字符串和参数将格式化字符串写入到输出流 public PrintStream printf(Locale l, String format, Object ... args)
以上2个方法,当 format 为 null 时,抛出 NPE.
2. 参数说明
format
format 是以百分号(%) 开头的格式说明字符串,具体格式如下
%[argument_index$][flags][width][.precision]conversion
可选的 argument_index 是十进制整数,表示参数列表中参数的位置。 第一个参数由“ 1$
”引用,第二个由“ 2$
” 引用 ,等等。 argument_index 必须紧跟 %
后面,并以 $
结束。
note: 参数索引值从1开始,而不是从0开始, %1$
对第一个参数格式化。这就避免了与0标志混淆。
可选 flags 指定格式化输出外观的各种标志。 有效标志集取决于 conversion。
可选 width是正十进制整数,表示要写入到输出的字符个数(注意对于浮点数:也包含小数点所占的1个字和 负数的负号所占的1个字符)。 当实际字符数小于指定的宽度时,最前面用 flags 指定的标志填充(若未指定,默认用空格)。
eg: v=2.3, %5.2f
输出 5.20
,且前面包含1个空格。共打印5个字符,整数位1个5,1个小数点,2个精度,长度为4,比指定的宽度少1为,用1个前导空格代替。
可选 precision 是一个非负十进制整数,通常用于限制字符数。 具体行为取决于转换。
conversion (必需) 是一个字符,指示如何格式化参数。 给定参数的有效转换集取决于参数的数据类型。
- 表1-用于printf flags(标志) 说明
标志 | 目的 | 示例 |
---|---|---|
+ | 打印正数和负数的符号 | +3333.33 |
空格 | 在正数之前添加空格 | | 3333.33| |
0 | 数字前面补0 | 003333.33 |
- | 左对齐(不指定-时,默认为右对齐) | |3333.33 | |
( | 将负数括在括号内 | %d,-90输出(90) |
,(英文逗号) | 添加分组分隔符,只对定点浮点数整数部分添加分组分隔符,小数部分不会添加 | 3,333.33 |
#(对于f格式) | 包含小数点 | 3,333. |
#(对于x或o格式) | 添加前缀0x或0 | 0xcafe |
$ | 指定要格式化的参数索引。例如,%1 d d %1 dx 将以十进制和十六进制格式打印第1个参数 | 159 9F |
< | <格式化前面说明的数值。例如, %d<%x 将以十进制和十六进制打印同一个值 | 159 9F |
- 表2-用于printf conversion(转换符) 说明
转换符 | 类型 | 示例 | 转换符 | 类型 | 示例 |
---|---|---|---|---|---|
d | 十进制整数 | 159 | s | 字符串 | hello |
x | 十六进制整数 | 9f | c | 字符 | H |
o | 八进制整数 | 237 | b | 布尔 | true |
f | 定点浮点数 | 1.59e+01 | h | 散列码 | 42628b2 |
e | 指数浮点数 | tx或Yx | 日期时间(T强制大写) | 已经过时,应当改为使用 java.time 类。 | |
g | 通用浮点数(e和f中较短的一个) | —— | % | 百分号 | % |
a | 16进制浮点数 | 0x1.fccdp3 | n | 与平台有关的换行符 | —— |
补充1: 使用 s 转换符格式化任意的对象
可以使用 s 转换符格式化任意的对象。 对于实现了 Formattable 接口的任意对象,将调用这个对象的 formatTo 方法;否则调用 toString 方法将这个对象转换为字符串。
补充2: String.format()
使用 String.format()
方法可创建一个格式化的字符串,而不打印输出。
API:
public static String format(String format, Object... args) public static String format(Locale l, String format, Object... args)
参数和 printf() 中的含义相同。
表3-日期和时间的转换符
Note: 以下格式符已经过时,对于新的代码,应当使用 java.time 包的方法。
eg:
System.out.printf("%tc",new Date());
这条语句将用下面的格式打印当前的日期和时间:
Mon Feb 09 18:05:19 PST 2015
下面的转换符前面都必须用 t/T 修饰。
转换符 | 类型 | 示例 |
---|---|---|
c | 完整的日期和时间 | Mon Feb 09 18:05:19 PST 2015 |
F | ISO 8601日期 | 2015/2/9 |
D | 美国格式的日期(月/日/年) | 02/09/2015 |
T | 24小时时间 | 18:05:19 |
r | 12小时时间 | 6:05:19 |
R | 24小时时间,没有秒 | 18:05 |
Y | 4位数字的年(前面补0 | 2015 |
y | 年的后两位数字(前面补0) | 15 |
C | 年的前两位数字(前面补0) | 20 |
B | 月的完整拼写 | February |
b或h | 月的缩写 | Feb |
m | 两位数字的月(前面补0) | 02 |
d | 两位数字的日(前面补0) | 09 |
e | 两位数字的日(前面不补0 | 9 |
A | 星期几的完整拼写 | Monday |
a | 星期几的缩写 | Mon |
j | 三位数的年中第几天(前面补0),在001到366之间 | 069 |
H | 两位数字的小时(前面补0),在0到23之间 | 18 |
k | 两位数字的小时(前面不补0),在0到23之间 | 18 |
I | 两位数字的小时(前面补0),在01到12之间 | 06 |
l | 两位数字的小时(前面不补0),在1到12之间 | 6 |
M | 两位数字的分钟(前面补0) | 05 |
S | 两位数字的秒(前面补0) | 19 |
L | 三位数字的毫秒(前面补0) | 047 |
N | 九位数字的毫微秒(前面补0) | 047000000 |
p | 上午或下午的标志 | pm |
z | 从 GMT 起,RFC 822 数字位移 | -800 |
Z | 时区 | PST |
s | 从格林尼治时间 1970-01-01 00:00:00 起的秒数 | 1078884319 |
Q | 从格林尼治时间 1970-01-01 00:00:00 起的毫秒数 | 1078884319047 |
从上表可以看到,某些格式只给出了指定日期的部分信息。
例如,只有日期或月份。如果需要多次提供日期来分别格式化每一部分就太笨拙了。
为此,可以用一个格式字符串指示要格式化的参数索引。
索引必须紧跟在%后面,并以$终止。
例如,
System.out.printf("%1$s %2$tB %2$te, %2$tY","Due date:",new Date());
会打印
Due date: February 9, 2015
还可以选择使用<标志。它指示前面格式说明中的参数将被再次使用。也就是说,以下语句将产生与前面语句同样的输出结果:
System.out.printf("%1$s %tB %<te, %<tY","Due date:",new Date());
args
args : 格式字符串中格式说明符引用的参数。
如果参数多于格式说明符,则忽略额外参数。
参数的数量是可变的,可以为零。
参数的最大数量受The Java Virtual Machine Specification(java虚拟机规范)定义的Java数组的最大维数限制。
null参数上的行为取决于 conversion(转换符) 。
locale
数字和日期的格式化规则是特定于本地化环境的。
例如,在德国,分组分隔符是点号而不是逗号,另外 Monday被格式化为 Montag。
locale主要用于如何控制应用的国际化行为。
3.printf 使用实例
// +199 199 c7 307 0xc7 0307 System.out.printf("%+d %<d %<x %<o %<#x %<#o\n",199); // | 23| |23| System.out.printf("|% d| |%<d|\n",23); // hello 第5个字符是o,that's true System.out.printf("%s 第%d个字符是%c,that's %b\n","hello",5,'o',true); // 15 % 6 = 3 System.out.printf("%2$d %% %1$d = %3$d\n",6,15, 15 % 6); // | 7.33| |007.33| |7.330000| 0x1.d51eb851eb852p2 System.out.printf("|%6.2f| |%0<6.2f| |%<f| %<a\n",7.33); // | 211.79| |211.79 | System.out.printf("|%7.2f| |%<-7.2f|\n",211.79); // | -211.79| |(211.79)| |(-211.79)| System.out.printf("|%8.2f| |%<(8.2f| |(%<.2f)|\n",-211.79); // |-21171.3333| |-21,171.3333| |-2.1171e+04| |-2.117e+04| System.out.printf("|%.4f| |%<,.4f| |%<.4e| |%<.4g|\n",-21171.3333); String str = new String("tree"); // Note: %h 格式符输出对象的散列码 和 调用对象的hashCode 得到的值并不相同 // obj %h formatinput: 36739e,hashCode:3568542 System.out.printf("obj %%h formatinput: %h,hashCode:%s\n",str,str.hashCode()); // true 25 0.0032 含 System.out.printf("%s %s %s %s\n",true,25,3.2e-3,'含'); System.out.printf("|%n| \n","world"); System.out.printf("|%n| \n");
输出
+199 199 c7 307 0xc7 0307
| 23| |23|
hello 第5个字符是o,that's true
15 % 6 = 3
| 7.33| |007.33| |7.330000| 0x1.d51eb851eb852p2
| 211.79| |211.79 |
| -211.79| |(211.79)| |(-211.79)|
|-21171.3333| |-21,171.3333| |-2.1171e+04| |-2.117e+04|
obj %h formatinput: 36739e,hashCode:3568542
true 25 0.0032 含
|
|
|
|
关于printf 转换符使用的注意事项
- 适用于浮点类型转换符(e,g,a,f)不能用于整形; 同样适用于整形的转换符(d,o,x)不能用于浮点型。
- 可以使用 s 转换符格式化任意的对象。对于实现了 Formattable 接口的任意对象,将调用这个对象的 formatTo 方法;否则调用 toString 方法将这个对象转换为字符串。
eg:
// test in jdk 8,11,14 // Exception in thread "main" java.util.IllegalFormatConversionException: o != java.lang.Float System.out.printf("%o\n",2.3f); // Exception in thread "main" java.util.IllegalFormatConversionException: f != java.lang.Integer System.out.printf("%f\n",25);
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。