天天看點

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());
/*第一個參數,他包含個格式符 "%1$tY", "%1$tm", "%1$td","%1$tH", "%1$tM","%1$tS",這些格式符
訓示如何處理參數以将他們插入到文本中,固定文本包括"Today is " 以及其他任何的空格和标點符号,比如
連接配接符“-”以及“:”。而格式字元串後面的參數組成了參數清單。在上面的示例中,參數清單的大小是并且由
Calendar 對象組成*/
           

格式符的文法如下:其中[]内部表示可選選項,沒有包含在[]内的表示必須要有的

%[argument_index$][flags][width][.precision]conversion

  1. argument_index表示參數索引,訓示需要的參數在參數清單中的位置。如果在第一個則用”1 "表示,第2個用"2 ”表示
  2. flags表示用來修改輸出格式的字元的集合,依賴于conversion
  3. width 是非負的整數,表示輸出字元的最小長度
  4. .precision 精度是非負的十進制整數,通常用來限制字元的個數,主要表示将數字格式化後,保留小數點後幾位
  5. 必須的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字元如下:

  1. ‘b’,’B’:轉化成boolean表示類型,比對boolean型參數,如果參數為null則格式化後格式符被替換為false,如果參數為boolean類型被替換為String.valueOf(arg)。如果不為空也不是boolean則替換為true.
  2. ‘h’, ‘H’:轉化參數為哈希碼格式,如果參數為null,則格式符替換為null,否則,替換為Integer.toHexString(arg.hashCode()),就是參數的hash碼的字元串表示
  3. ’s’,’S’:如果參數為null,則替換為null,如果參數實作了Formattable接口,則用執行arg.formatTo方法的結果替換格式符,否則用toString()結果替換格式符
  4. ‘c’, ‘C’:轉化成Unicode字元格式
  5. ‘d’:轉化成整數格式
  6. ‘o’:轉化成8進制數格式
  7. ‘x’, ‘X’:轉化成16進制格式
  8. ‘e’, ‘E’:把浮點數轉成科學計數法格式的
  9. ‘f’:轉成浮點數格式
  10. ‘g’, ‘G’:根據四舍五入規則和精度轉成科學技術格式或數字格式
  11. ‘a’, ‘A’:轉成16進制浮點數
  12. ‘t’, ‘T’:轉成時間日期格式
  13. ‘%’:轉成百分号(‘\u0025’)
  14. ‘n’:轉成分行符

    日期時間的conversions字元字首是”t” 和 “T”,還需要提供額外的conversion

  15. ‘H’:24小時制的小時數,顯示兩位00-23
  16. ‘I’:12小時制的顯示01-12
  17. ‘k’:24小時制0-23,與“H”的差別就是當0-9點時,顯示1位,而”H”會補0顯示兩位
  18. ‘l’:12小時制1-12,小于10點不補0
  19. ‘M’:轉化分鐘,顯示00-59,顯示兩位
  20. ‘S’:轉化秒,顯示00-60,顯示兩位
  21. ‘L’:轉化毫秒,顯示000 - 999.
  22. ‘N’:轉化成時間毫秒數,顯示000000000 - 999999999.
  23. ‘p’:上下午,顯示am或者pm
  24. ‘z’:時區
  25. ‘Z’:時區
  26. ’s’:從1970年開始計算的秒數,相當于毫秒數除以1000
  27. ‘Q’:1970年開始的毫秒數即date.getTime()傳回的毫秒數
  28. ‘B’: 轉成本地月份的全稱,例如”January”, “February”.
  29. ‘b’:轉成本地月份的簡稱 “Jan”, “Feb”.
  30. ‘h’:和’b’一樣.
  31. ‘A’:轉成本地星期的全稱.例如 “Sunday”, “Monday”
  32. ‘a’:轉成本地星期的簡寫.如 “Sun”, “Mon”
  33. ‘C’:年頭兩位顯示00 - 99,比如2015顯示20
  34. ‘Y’:年,4位,例如2015
  35. ‘y’:年後2位,00 - 99.2015顯示15
  36. ‘j’:當年的第多少天 顯示001-366
  37. ‘m’:轉成數字的月顯示01-13
  38. ‘d’:轉成日子,即當月第多天,顯示01 - 31
  39. ‘e’:轉成日子,1位,小于10不補0 顯示1-31

    可以用來代替格式化日期的組合conversions字元

  40. ‘R’:可以表示”%tH:%tM”組合,即%tR = %tH:%tM;
  41. ‘T’:可以表示”%tH:%tM:%tS”組合,即%tT = “%tH:%tM:%tS”;
  42. ‘r’:可以表示”%tI:%tM:%tS %Tp”.
  43. ‘D’:可以表示”%tm/%td/%ty”.
  44. ‘F’:可以表示”%tY-%tm-%td”.
  45. ‘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());//輸出-- ::
/*不解釋了,如何輸出格式化日期字元串,就靠他了*/
           

“`