JDK 1.5 开始,String 类中提供了一个非常有用的方法 String.format()
,极大的方便了格式化输出,该方法有两种重载形式:
- String.format(String format, Object … args)
使用本地语言环境,制定字符串格式和参数生成格式化的新字符串。
- String.format(Locale l, String format, Object… args)
使用指定语言环境,制定字符串格式和参数生成格式化的新字符串。
一、语法说明
查看 JDK 文档得知,String.format()
方法的参数 format
是有规则和格式可遵循的,规则如下:
%[argument_index$][flags][width][.precision]conversion
参数 | 含义 | 功能描述 | 备注 |
---|---|---|---|
% | 起始字符 | 起始字符,若要在占位符内部使用%,则需要写成 %% | 必选 |
argument_index$ | 索引 | 位置索引从1开始计算,用于表明参数在参数列表中的位置 | 可选 |
flags | 标识 | 控制输出格式,可多个同时使用,但某些标识不能同时使用 | 可选 |
width | 最小宽度 | 设置格式化后的字符串最小宽度,若使用 [width] 而无设置 [flags],那么当字符串长度小于最小宽度时,则以左边补空 格的方式凑够最小宽度 |
可选 |
.precision | 精度 | 用于浮点数类型格式化,设置保留小数点后多少位 | 可选 |
conversion | 转换符 | 用于指定格式化的样式,和限制对应入参的数据类型 | 必选 |
下面通过几个例子的使用来说明格式化规则中参数的作用和用法:
1 | 【代码】System.out.println(String.format("我是%s", "曹操")); |
上面的代码只使用了%s
这个简单的表达式,对比规则会发现[argument_index$][flags][width][.precision]
这些部分全都省略掉了,只留下一个必须的conversion
,在这里conversion
对应s
,百分号%
是固定不变的。如果格式化表达式省略[argument_index$]
,则后面的值会按照默认顺序依次填充表达式中的占位符。例如上面的例子中,”曹操” 默认填充到了一号位。下面的例子演示了多个参数情况下,依次填充占位符的情形:
1 | 【代码】System.out.println(String.format("我是%s,他是%s", "曹操", "刘备")); |
如果在上面例子的基础上添加[argument_index$]
参数,就可以指定占位符的取值顺序,案例如下:
1 | 【代码】System.out.println(String.format("我是%2$s,他是%1$s", "曹操", "刘备")); |
对比以上两个例子会发现取值顺序发生了变化。那么conversion
除了可以为s
外,还有什么其他格式可以选择呢?当然有,比如:
o : 结果被格式化为八进制整
x : 结果被格式化为十六进制
d : 结果被格式化为十进制整
1 | 【代码】System.out.println(String.format("%o", 8)); |
至此,我们已经了解了[argument_index$]
和conversion
的用处,接下来我们了解[flag]
和[width]
的用法,[flag]
是用来控制输出格式的,比如左对齐、金额用逗号隔开等;[width]
表示最小宽度。先来看个例子:
1 | 【代码】System.out.println(String.format("%1$,d", 99999999)); |
这里多出的逗号,
就是[flag]
,用于将金额千分位隔开,上面例子中的第二行代码是省略掉[argument_index$]
参数后的表达式,经过运行会发现和第一行代码的运行结果一样。再看一个例子:
1 | 【代码】System.out.println(String.format("%1$08d", 123456)); |
这里 0 对应[flag]
,表示结果将用零来填充;8 对应[width]
,表示结果最少要 8 位;d 对应conversion
。接下来说说[.precision]
参数,这个单词是精度的意思,我们发现前面有个小数点.
,因此不难联想到这是个和浮点数类型相关的参数,只有传入的数据是浮点数时才有用,整数或者日期类型的数据都不能用。如果想要四舍五入保留两位小数,那么可以这么写:
1 | 【代码】System.out.println(String.format("%1$.2f", 93.12645)); |
这里的f
表示传入的数字是浮点型,如果传入的是整数或者把f
改成d
都会抛出异常。对于浮点转换e
、E
和f
,精度是小数点分隔符后的位数。如果转换是g
或G
,那么精度是舍入计算后所得数值的所有位数。如果转换是a
或A
,则不必指定精度。
对于字符、整数和日期/时间参数类型转换,以及百分比和行分隔符转换,精度是不适用的;如果提供精度,则会抛出异常。
到此为止,这套表达式公式已经基本讲完了。这套公式是针对基本数据类型和字符串的,如果是针对时间类型的数据该怎么做呢,比如格式化日期?其实文档中已经给出说明,用来表示日期和时间类型的格式说明符的语法如下:
%[argument_index$][flags][width]conversion
可选的 [argument_index$][flags][width]
的意义同上。所需的 conversion 是一个由两字符组成的序列。第一个字符是t
或 T
。第二个字符表明所使用的格式。这些字符类似于但不完全等同于那些由 GNU date 和 POSIX strftime(3c) 定义的字符。需要注意的是conversion
**是一个由两字符组成的序列。**第一个字符是t
或T
。也就是说用conversion
的时候首先必要写一个t
,然后在写其它conversion
。时间类型有它自己的一套 conversion,我们简单的选择几个来说:
参数 | 含义 | 说明 |
---|---|---|
Y | 年份 | 被格式化为必要时带前导零的四位数(至少),例如,0092 等于格里高利历的 92 CE。 |
m | 月份 | 被格式化为必要时带前导零的两位数,即 01 - 12 |
d | 天数 | 被格式化为必要时带前导零的两位数,即 01 - 31 |
上面三个分别表示年月日,如果要显示年份,可以写成%tY
,显示月份可以写%tm
,记得一定要带上t
。
二、测试用例
转换符 | 说明 | 示例 |
---|---|---|
%s | 字符串类型 | “name” |
%c | 字符类型 | ‘c’ |
%b | 布尔类型 | true |
%d | 整数类型(十进制) | 99 |
%x | 整数类型(十六进制) | FF |
%o | 整数类型(八进制) | 77 |
%f | 浮点类型 | 99.99 |
%a | 十六进制浮点类型 | FF.35AE |
%e | 指数类型 | 9.38e+5 |
%g | 通用浮点类型(f和e类型中较短的) | 42.5000 |
%h | 散列码 | 41 |
%% | 百分比类型 | % |
%n | 换行符 | %n |
%tx | 日期与时间类型(x代表不同的日期与时间转换符) | 2017-07-05 |
格式化 | 输出 |
---|---|
String.format(“Hi,%s”, “中国”) | Hi,中国 |
String.format(“Hi,%s:%s.%s”, “中国”, “美国”, “英国”) | Hi,中国:美国.英国 |
String.format(“字母 a 的大写是:%c”, ‘A’) | 字母 a 的大写是:A |
String.format(“3 < 7 的结果是:%b”, 3 < 7) | 3 < 7 的结果是:true |
String.format(“100 的一半是:%d”, 100 / 2) | 100 的一半是:50 |
String.format(“100 的 16 进制数是:%x”, 100) | 100 的 16 进制数是:64 |
String.format(“100 的 8 进制数是:%o”, 100) | 100 的 8 进制数是:144 |
String.format(“50 元打 8.5 折是:%f 元”, 50 * 0.85) | 50 元打 8.5 折是:42.500000 元 |
String.format(“50 的 16 进制数是:%a”, 50 * 0.85) | 50 的 16 进制数是:0x1.54p5 |
String.format(“50 x 0.85 指数表示:%e”, 50 * 0.85) | 50 x 0.85 指数表示:4.250000e+01 |
String.format(“通用浮点类型:%g”, 50 * 0.85) | 通用浮点类型:42.5000 |
String.format(“已下载%d%%”, 85) | 已下载85% |
String.format(“字母 A 的散列码是:%h”, ‘A’) | 字母 A 的散列码是:41 |
String.format(“换行符的使用:%s %n”, “ABC”) | 换行符的使用:ABC |
String.format(“%1$tY-%1$tm-%1$td”, new Date()) | 2017-07-05 |