package io; import java.util.GregorianCalendar; import java.util.TimeZone; /** * Java 的格式化输出 * Java 的格式化输出一般用于下面几种情况 * (1)String.format(String formatter,agr...) * (2)System.out.printf(String formatter,agr...) * (3)PrintWriter.printf(String formatter,agr...) * 上面三种典型用法中,都是根据一个字符串格式的formatter和一个参数列表,获得一个格式化的字符串. * 其功能类似于c语言中的pringf函数. * 参数formatter有固定的语法,主要语法有下面三种: * * (1)常规类型、字符类型和数值类型的格式说明符的语法如下: * * %[argument_index$][flags][width][.precision]conversion * * %: 这个是参数转换格式化串的起点 * argument_index$: 由argument_index和$构成,表示使用后面参数列表中第argument_index参数来获取格式化字符 * flags: 是一些标志,比如 - 可以将参数左对齐,这个根据后面参数的具体类型有不同的标志可选用 * width: 表示将后面参数格式化后的宽度,比如宽度为3,并使用-作为flag后,格式化整数5后,得到的字符串为"5 ",即5后面加2空格 * .precision: 表示精度,这个一般针对浮点数,比如3.1415929 使用"%.2f"格式化之后得到3.14 * conversion:是格式化规则,比如上面的"%.2f"中的f就是一个规则,f只能对应浮点型参数,否则会抛异常 * conversion也是参数格式化串的终点 * * 上面format(String formatter,agr...)中的formatter可以包含很多的参数格式化串, * 也可以包含非格式化串,这些非格式化串字符将按照原样输出. * * 比如调用format("小明今年 %2$-3d岁,生于 %1$-5d年.",1994,20) * 得到的格式化之后的字符串为:小明今年 20 岁,生于 1994 年. * 注意,上面的formatter中包含两个格式化串:%2$-3d 和 %1$-5d,都是以%开头,d(conversion)结尾的. * 其他部分,是非格式化串字符,比如"小明今年 "则按原样输出. * %2$-3d中的2$表示使用后面的第二个参数,也就是20.注意这里20是2个宽度,而-3表示格式化成3个宽度并且左对齐, * 这样得到的输出就是"20 岁",20和岁之间加了一个空格,以是的20格式化之后的宽度变成3. * * (2)用来表示日期和时间类型的格式说明符的语法如下: * * %[argument_index$][flags][width]conversion * * 这个跟上面的有两点区别:首先,格式化时间不需要[.precision]这个了; * 其次,格式化时间的conversion 有特殊要求,即,必须要在前面加一个t或T. * 有一些专门的conversion用于格式化时间,使用这些conversion时,需要在前面加一个t * * 比如, * Calendar c = new GregorianCalendar(1984, 6, 4); * String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c); * 这里%1$tm中的m是conversion,表示输出两位数月份,t是前缀. * 格式化之后得到:Duke's Birthday: 07 4,1984 * * (3)与参数不对应的格式说明符的语法如下: * * %[flags][width]conversion * * 这个与前面(1)的区别是去掉了[argument_index$]和[.precision]表示: * 首先,不能指定参数位置与格式化串的对应关系,则使用格式化串的位置寻找后面对应位置的参数 * format("小明今年 %-3d岁,生于 %-5d年.",1994,20) * 上面的格式化串%-3d位置为1,则使用第一个参数1994来获取格式化串, * 最终返回"小明今年 1994岁,生于 20 年." 这样就不对了. * 所以,后面的参数位置要和前面的格式化串对应.改成: * format("小明今年 %-3d岁,生于 %-5d年.",20,1994) * * */ public class TestStringFormat { public static void main(String[] args) { //格式化输出整数 String str1 = String.format("小明今年 %2$-3d岁,生于 %1$-5d年.",1994,20); System.out.println(str1); //输出:小明今年 20 岁,生于 1994 年. //没有参数对应时,要让格式化串和参数的顺序对应好 str1 = String.format("小明今年 %-3d岁,生于 %-5d年.",20,1994,20); System.out.println(str1); //输出:小明今年 20 岁,生于 1994 年. //没有参数对应时,参数数量少于格式化串数量时,格式化串变成空, //参数多了则没关系(参考上面的20,1994,20三个参数只用到了两个) //有参数对应时,如果用3$指定了第三个参数,而参数列表中只有2个参数则会报错 //str1 = String.format("小明今年 %2$-3d岁,生于 %1$-5d年.",1994);//这样的报错 //格式化日期,时间 GregorianCalendar c = new GregorianCalendar(1984, 6, 4,12,22,33);//构造制定日期时间的日历 c.setTimeZone(TimeZone.getTimeZone("GMT+8")); c.setTimeInMillis(System.currentTimeMillis());//设置为当前日期时间 str1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c); System.out.println(str1);//输出:Duke's Birthday: 02 27,2014 str1 = String.format("Time: %1$tH:%1$tM:%1$tS",c); System.out.println(str1);//输出: Time: 20:19:09 //格式化浮点数,如果浮点数格式化后小数位数小于原来的值,则是按照四舍五入方式 舍弃的 str1 = String.format("π值为 %1$s,浮点数为:%1$f,精确到3位小数为:%1$.3f", 3.1415926); System.out.println(str1);//输出:π值为 3.1415926,浮点数为:3.141593,精确到3位小数为:3.142 //格式化输出数组,左对齐,每个整数占5个宽度 int[][] dataArr = {{1,2,3},{4,5,6}}; for(int i=0;i<2;i++) { for(int j=0;j<3;j++) { System.out.printf("%-5d",dataArr[i][j]); } System.out.println(""); } /* * 输出: * 1 2 3 * 4 5 6 */ } }