Java Appeandable介面與字串格式化
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
/*不解釋了,如何輸出格式化日期字串,就靠他了*/
“`