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
*/
}
}