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());
/*第一個參數,他包含個格式符 "%1$tY", "%1$tm", "%1$td","%1$tH", "%1$tM","%1$tS",這些格式符
訓示如何處理參數以将他們插入到文本中,固定文本包括"Today is " 以及其他任何的空格和标點符号,比如
連接配接符“-”以及“:”。而格式字元串後面的參數組成了參數清單。在上面的示例中,參數清單的大小是并且由
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的符号
. '-':右對齊
. '#':使用conversion-dependent形式的替代
. '+':結果會包含符号
. ' ':結果會為正數前面保留一個空格
. '0':如果是正整數的話,那麼不足位數的話會在結果前面會補
. ',':結果包含分組符例如 ,,每三為分組
. '(':結果将會包在括号中
幾個示例:
//格式化輸出數字,位,不足位前面補
formatter.format("This number is %1$04d .", );//輸出This number is
/*格式符"%1$04d",其中argment_index=,flags是'0',width是,conversions符号是d,
表示格式符要表示的是一個整數,用參數替換,要格式化為位整數,如果參數表示的正整數不足
位,那麼要在前面補,則"%1$04d"最終轉為*/
//格式化為進制
formatter.format("This number is 0x%1$04X .", );//輸出This number is
/*格式符"%1$04X",其中argment_index=,flags是'0',width是,conversions符号是X,
表示格式符要表示的是一個十六進制整數,用參數替換,同時将參數轉化為進制格式,并且要格式
化為位,如果不足位,那麼要在前面補,則"%1$04X"最終轉為F*/
//根據四舍五入規則和精度轉成科學計數格式或數字格式
formatter.format("This number is %1$+.4G .",);//輸出This number is +
/*格式符"%1$+.4G",其中argment_index=,flags是'+',是.precision是.,conversions
符号是G,表示格式符要表示的是一個規格化的浮點數,用參數替換,flags表示要在數字前面加符
号,如果是正數則加'+',‘.’表示精度,即浮點數算上小數點後隻能有位,如果不足位則在後面補
,%1$+.G轉成了+*/
//以yyyy-MM-dd HH:mm:ss格式輸出日期
formatter.format("Today is %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance());//輸出-- ::
/*不解釋了,如何輸出格式化日期字元串,就靠他了*/
“`