1.java.lang.Appendable接口
首先看接口java.lang.Appendable的用途,文档中是这样说的:The Appendable interface must be implemented by any class whose instances are intended to receive formatted output from a Formatter.也就说,只有实现了Appendable接口的类实例,才能接收Formatter类的格式化输出。也就是说Formatter类格式化好了一个字符串,必须使用一个实现了Appendable接口的类实例去存储这个字符串。
2.java.util.Formatter类
然后我们看java.util.Formatter类:该类是一个格式化字符串的解释器,他提供字符串的对齐和居中布局,以及将数字,时间日期,字符串等按照普通格式进行格式化输出的支持。普通的java类型例如byte, BigDecimal, 以及Calendar等都被支持并且对实现了Formattable接口的任意用户自定义类型提供有限的支持。
Formatter在多线程环境下不一定是安全的,线程安全由用户负责。
Formatter格式化输出受到了C语言printf方法的启发
String静态方法format和Formatter的功能一样
3.java.lang.Appendable接口与java.util.Formatter类的关系
首先看java.util.Formatter的构造函数:java.util.Formatter(java.lang.Appendable a),参数a是用来接收格式化好的字符串的,如果a为null,jva.util.Formatter会提供一个java.lang.StringBuilder类实例来接收格式化输出,可以通过formatter.out()方法获取接收了格式化输出的java.lang.Appendable实例。任何实现了java.lang.Appendable接口的实例都可以接收java.util.Formatter类的实例通过format方法处理输出的字符串,比如String,StringBuffer,StringBuilder,File,OutputStream等。
//可以创建Appendable接口的实现类对象来作为Formatter对象的foramtter方法输出的接收类
Appendable dest = new String() 或 new StringBuffer() 或 new File("D:\\destFile.txt") 或 new Appendable(){
public Appendable append(CharSequence csq) throw IOException{
//用户自定义
}
......
};
Formatter formatter = new Formatter(dest);
formatter.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance());
上述代码使用formatter格式化了一个日期字符串(时间是2015-03-23 11:10:37),format方法在运行过程中,生成了一个“yyyy-MM-dd HH:mm:ss”格式的日期字符串“2015-03-23 11:10:37”,该日期字符串会保存在Appendable实例dest中。如果dest是一个String类型的对象,那么dest的值就是“2015-03-23 11:10:37”,如果dest是一个file对象,那么字符串“2015-03-23 11:10:37”会被写入到文件dest中。总之,formatter方法在生成格式化好的字符串后,会调用dest的append方法将输出写入到用来接收输出的Appeandable实例dest中
java字符串格式化使用说明书
任何产生格式化输出的方法都要求一个格式字符串以及参数列表。格式字符串是一个含有固定文本以及嵌入1个或者多个格式符的字符串。
Formatter formatter = new Formatter(dest);
formatter.format("Today is %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance());
/*第一个参数,他包含6个格式符 "%1$tY", "%1$tm", "%1$td","%1$tH", "%1$tM","%1$tS",这些格式符
指示如何处理参数以将他们插入到文本中,固定文本包括"Today is " 以及其他任何的空格和标点符号,比如
连接符“-”以及“:”。而格式字符串后面的参数组成了参数列表。在上面的示例中,参数列表的大小是1并且由
Calendar 对象组成*/
格式符的语法如下:其中[]内部表示可选选项,没有包含在[]内的表示必须要有的
%[argument_index$][flags][width][.precision]conversion
- argument_index表示参数索引,指示需要的参数在参数列表中的位置。如果在第一个则用”1"表示,第2个用"2”表示
- flags表示用来修改输出格式的字符的集合,依赖于conversion
- width 是非负的整数,表示输出字符的最小长度
- .precision 精度是非负的十进制整数,通常用来限制字符的个数,主要表示将数字格式化后,保留小数点后几位
- 必须的conversion 是一个字符,指示参数应该如何格式化,有效的conversion集合依赖参数数据的类型,而上例中的conversion是tm、te、tY,上例中flags、width、.Precision都没有,因为可选,所以可以没有,但conversion必须有
conversions类型分成6大类:
1.通用的,任何类型的参数都可以用
2.字符的,Character,只表示基本类型,char byte short等占2个字节或以下的类型,如果Integer在Character.isValidCodePoint(int) 为true时也可以使用
3.数字的,又分为正型和浮点型
4.时间日期。支持long,calendar,date,以及 TemporalAccessor型,时间日期conversions一般是两位
5.百分比,产生 a literal ‘%’ (‘\u0025’)
6.换行符,产生特定平台的换行符
常用的conversions字符如下:
- ‘b’,’B’:转化成boolean表示类型,匹配boolean型参数,如果参数为null则格式化后格式符被替换为false,如果参数为boolean类型被替换为String.valueOf(arg)。如果不为空也不是boolean则替换为true.
- ‘h’, ‘H’:转化参数为哈希码格式,如果参数为null,则格式符替换为null,否则,替换为Integer.toHexString(arg.hashCode()),就是参数的hash码的字符串表示
- ’s’,’S’:如果参数为null,则替换为null,如果参数实现了Formattable接口,则用执行arg.formatTo方法的结果替换格式符,否则用toString()结果替换格式符
- ‘c’, ‘C’:转化成Unicode字符格式
- ‘d’:转化成整数格式
- ‘o’:转化成8进制数格式
- ‘x’, ‘X’:转化成16进制格式
- ‘e’, ‘E’:把浮点数转成科学计数法格式的
- ‘f’:转成浮点数格式
- ‘g’, ‘G’:根据四舍五入规则和精度转成科学技术格式或数字格式
- ‘a’, ‘A’:转成16进制浮点数
- ‘t’, ‘T’:转成时间日期格式
- ‘%’:转成百分号(‘\u0025’)
- ‘n’:转成分行符
日期时间的conversions字符前缀是”t” 和 “T”,还需要提供额外的conversion - ‘H’:24小时制的小时数,显示两位00-23
- ‘I’:12小时制的显示01-12
- ‘k’:24小时制0-23,与“H”的区别就是当0-9点时,显示1位,而”H”会补0显示两位
- ‘l’:12小时制1-12,小于10点不补0
- ‘M’:转化分钟,显示00-59,显示两位
- ‘S’:转化秒,显示00-60,显示两位
- ‘L’:转化毫秒,显示000 - 999.
- ‘N’:转化成时间毫秒数,显示000000000 - 999999999.
- ‘p’:上下午,显示am或者pm
- ‘z’:时区
- ‘Z’:时区
- ’s’:从1970年开始计算的秒数,相当于毫秒数除以1000
- ‘Q’:1970年开始的毫秒数即date.getTime()返回的毫秒数
- ‘B’: 转成本地月份的全称,例如”January”, “February”.
- ‘b’:转成本地月份的简称 “Jan”, “Feb”.
- ‘h’:和’b’一样.
- ‘A’:转成本地星期的全称.例如 “Sunday”, “Monday”
- ‘a’:转成本地星期的简写.如 “Sun”, “Mon”
- ‘C’:年头两位显示00 - 99,比如2015显示20
- ‘Y’:年,4位,例如2015
- ‘y’:年后2位,00 - 99.2015显示15
- ‘j’:当年的第多少天 显示001-366
- ‘m’:转成数字的月显示01-13
- ‘d’:转成日子,即当月第多天,显示01 - 31
- ‘e’:转成日子,1位,小于10不补0 显示1-31
可以用来代替格式化日期的组合conversions字符 - ‘R’:可以表示”%tH:%tM”组合,即%tR = %tH:%tM;
- ‘T’:可以表示”%tH:%tM:%tS”组合,即%tT = “%tH:%tM:%tS”;
- ‘r’:可以表示”%tI:%tM:%tS %Tp”.
- ‘D’:可以表示”%tm/%td/%ty”.
- ‘F’:可以表示”%tY-%tm-%td”.
- ‘c’:可以表示”%ta %tb %td %tT %tZ %tY”
例如
formatter.format("Today is %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance());
formatter.format("Today is %1$tF %1$tT", Calendar.getInstance());
/*这两种方式的结果是一样的,%1$tF转化结果等效于 %1$tY-%1$tm-%1$td的组合
%1$tT等效于%1$tH:%1$tM:%1$tS的组合*/
Flags的符号
46. '-':右对齐
47. '#':使用conversion-dependent形式的替代
48. '+':结果会包含符号
49. ' ':结果会为正数前面保留一个空格
50. '0':如果是正整数的话,那么不足位数的话会在结果前面会补0
51. ',':结果包含分组符例如 1000,000,000每三为分1组
52. '(':结果将会包在括号中
几个示例:
//格式化输出数字,4位,不足4位前面补0
formatter.format("This number is %1$04d .", 1);//输出This number is 0001
/*格式符"%1$04d",其中argment_index=1,flags是'0',width是4,conversions符号是d,
表示格式符要表示的是一个整数,用参数1替换,要格式化为4位整数,如果参数表示的正整数不足4
位,那么要在前面补0,则"%1$04d"最终转为0001*/
//格式化为16进制
formatter.format("This number is 0x%1$04X .", 15);//输出This number is 0x000F
/*格式符"%1$04X",其中argment_index=1,flags是'0',width是4,conversions符号是X,
表示格式符要表示的是一个十六进制整数,用参数1替换,同时将参数1转化为16进制格式,并且要格式
化为4位,如果不足4位,那么要在前面补0,则"%1$04X"最终转为000F*/
//根据四舍五入规则和精度转成科学计数格式或数字格式
formatter.format("This number is %1$+.4G .",15.23278);//输出This number is +15.23
/*格式符"%1$+.4G",其中argment_index=1,flags是'+',是.precision是.4,conversions
符号是G,表示格式符要表示的是一个规格化的浮点数,用参数1替换,flags表示要在数字前面加符
号,如果是正数则加'+',‘.4’表示精度,即浮点数算上小数点后只能有4位,如果不足4位则在后面补
0,%1$+.4G转成了+15.23*/
//以yyyy-MM-dd HH:mm:ss格式输出日期
formatter.format("Today is %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance());//输出2015-03-23 14:01:51
/*不解释了,如何输出格式化日期字符串,就靠他了*/
“`