一、前言
剛開始從.net的轉(zhuǎn)向java的時候總覺得 String.format 用得不習(xí)慣,希望格式模版會這樣 {0}, this is {1}'s cat.{1},this is {0}'s dog. 而不是 %1$s,this is %2$s's cat.%2$s,this is %1$s's dog. 。后來發(fā)現(xiàn) java.text.MessageFormat.format 可以滿足我這個小小的愿望。
二、靜態(tài)方法 java.text.MessageFormat.format
方法定義:
String MessageFormat.format(String fmt, Object...args)入?yún)mt為MessageFormat模式參數(shù)。
三、MessageFormat模式
格式: ArgumentIndex[,FormatType[,FormatStyle]]
ArgumentIndex ,是從0開始的入?yún)⑽恢盟饕?/p>
FormatType ,指定使用不同的Format子類對入?yún)⑦M行格式化處理。值范圍如下:
number:調(diào)用NumberFormat進行格式化
date:調(diào)用DateFormat進行格式化
time:調(diào)用DateFormat進行格式化
choice:調(diào)用ChoiceFormat進行格式化
FormatType ,設(shè)置FormatType中使用的格式化樣式。值范圍如下:
short,medium,long,full,integer,currency,percent,SubformPattern(子格式模式,形如#.##)
注意: FormatType 和 FormatStyle 主要用于對日期時間、數(shù)字、百分比等進行格式化。
示例——將數(shù)字1.23格式為1.2:
double num = 1.23;String str = MessageFormat.format("{0,number,#.#}", num);
四、MessageFormat注意點
1. 兩個單引號才表示一個單引號,僅寫一個單引號將被忽略。
2. 單引號會使其后面的占位符均失效,導(dǎo)致直接輸出占位符。
MessageFormat.format("{0}{1}", 1, 2); // 結(jié)果12MessageFormat.format("'{0}{1}", 1, 2); // 結(jié)果{0}{1}MessageFormat.format("'{0}'{1}", 1, 2); // 結(jié)果{0}因此可以用于輸出左花括號(單寫左花括號會報錯,而單寫右花括號將正常輸出)
MessageFormat.format("'{'{0}}", 2); // 結(jié)果{2因此前言中的示例應(yīng)該寫為
{0}, this is {1}''s cat.{1},this is {0}''s dog.
五、類層級關(guān)系
|-- java.text.MessageFormat
頂層抽象類java.text.Format—| |--java.text.ChoiceFormat
|--java.text.NumberFormat—|
| |--java.text.DecimalFormat
|
|--java.text.DateFormat—java.text.SimpleDateFormat
1. DecimalFormat
用于格式化十進制實數(shù)。通過格式字符串來自定義格式化類型,舍入方式為half-even(四舍五入)。
格式化模式: 正數(shù)子模式;負數(shù)子模式 ,如 0.00;-0.00 ,簡寫為 0.00 。
模式中的占位符:
0 ,代表該為位為數(shù)字,若不存在則用0填充
# ,代表該為位為數(shù)字
, ,代表分隔符, 如模式為 #,# ,那么格式化10時會返回1,0
2. ChoiceFormat
相當(dāng)于以數(shù)字為鍵,字符串為值的鍵值對。分別使用一組double類型的數(shù)組作為鍵,一組String類型的數(shù)組作為值,兩數(shù)組相同索引值的元素作為一對。
示例——基本用法
double[] limit = {0,1,3};String[] format = {"hello0", "hello1", "hello3"};ChoiceFormat cf = new ChoiceFormat(limit, format);for(int i = 0; i < 4; ++i){ System.out.PRintln(cf.format(i));}/* 輸出 * hello0 * hello1 * hello0 * hello3 */注意:當(dāng)找不到對應(yīng)的鍵值對時,則使用第一或最后一對鍵值對。
示例——結(jié)合MessageFormat使用
double[] limit = {0, 1};String[] format = {"Hello0", "Hello1{1}"};ChoiceFormat cf = new ChoiceFormat(limit, format);MessageFormat mf = new MessageFormat("{0}");mf.setFormatByArgumentIndex(0, cf);for (int i = 0; i < 2; ++i){ System.out.println(mf.format(new Object[]{new Integer(i), new Integer(i+1)}));}/* 輸出 * Hello0 * Hello12 */
六、性能問題
由于靜態(tài)方法 MessageFormat.format 內(nèi)部是
public static String format(String pattern, Object ... arguments) { MessageFormat temp = new MessageFormat(pattern); return temp.format(arguments); }因此若要多次格式同一個模式的字符串,那么創(chuàng)建一個MessageFormat實例在執(zhí)行格式化操作比較好些。
七、總結(jié)
對于簡單的格式化或字符串組裝, MessageFormat.format方法 使用更方便些,但要格式化處理更豐富的話要是用 String.format方法 吧!
尊重原創(chuàng), ^_^肥仔John
---------------------------------------------------------------------------------------------------------------------------------------MessageFormatMessageFormat.formatMessageFormat用來格式化一個消息,通常是一個字符串,比如:
String str = "I'm not a {0}, age is {1,number,short}", height is {2,number,#.#};
而MessageFormat可以格式化這樣的消息,然后將格式化后的字符串插入到模式中的適當(dāng)位置,比如:
將str中的{0}用"pig"替換,{1,number,short}用數(shù)字8替換,{2,number,#.#}用數(shù)字1.2替換。
那么最終用戶得到的是一個格式化好的字符串"I'm not a pig, age is 8, height is 1.2"。
MessageFormat本身與語言環(huán)境無關(guān),而與用戶提供給MessageFormat的模式和用于已插入?yún)?shù)的子格式模式有關(guān),以生成適用于不同語言環(huán)境的消息。
MessageFormat模式(主要部分):
FormatElement: { ArgumentIndex } { ArgumentIndex , FormatType } { ArgumentIndex , FormatType , FormatStyle }
FormatType: number
date
time
choice(需要使用ChoiceFormat)
FormatStyle: short medium long full integer currency percent SubformatPattern(子模式)
還以str為例,在這個字符串中:
1、{0}和{1,number,short}和{2,number,#.#};都屬于FormatElement,0,1,2是ArgumentIndex。
2、{1,number,short}里面的number屬于FormatType,short則屬于FormatStyle。
3、{1,number,#.#}里面的#.#就屬于子格式模式。
指定FormatType和FormatStyle是為了生成日期格式的值、不同精度的數(shù)字、百分比類型等等。
實例:
1、ArgumentIndex必須是非負整數(shù),它的個數(shù)不只限于0到9這10個,它可以用0到9的數(shù)字組成,因此可以有好多個,如:
Java代碼String pig = "{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}"; Object[] array = new Object[]{"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q"}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:ABCDEFGHIJKLMNOPQ
2、格式化字符串時,兩個單引號才表示一個單引號,單個單引號會被省略,如:
Java代碼String message = "oh, {0} is 'a' pig"; Object[] array = new Object[]{"ZhangSan"}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:oh, ZhangSan is a pig
給字母a加上單引號,如:
Java代碼String message = "oh, {0} is ''a'' pig"; Object[] array = new Object[]{"ZhangSan"}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:oh, ZhangSan is 'a' pig
3、單引號會使某個字符或串保持原形。
所以,假如沒有特殊要求,一般都是要在正式格式化之前把單引號都去掉,否則會造成不必要的麻煩,如:
Java代碼String message = "oh, '{0}' is a pig"; Object[] array = new Object[]{"ZhangSan"}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:oh, {0} is 'a' pig,此處ZhangSan無法顯示。
又如,使用子格式模式,多了一個單引號:
Java代碼String message = "oh, '{0,number,#.#} is a pig"; Object[] array = new Object[]{new Double(3.1415)}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:oh, {0,number,#.#} is 'a' pig。
如果像下面這樣,就可以正確顯示:
Java代碼String message = "oh, {0,number,#.#} is a pig"; Object[] array = new Object[]{new Double(3.1415)}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:oh, 3.1 is a pig
3、無論是有引號字符串還是無引號字符串,左花括號都是不支持的,但支持右花括號顯示,如:
Java代碼String message = "oh, { is a pig"; Object[] array = new Object[]{"ZhangSan"}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:異常java.lang.IllegalArgumentException: Unmatched braces in the pattern
右花括號可以顯示,如:
Java代碼String message = "oh, } is a pig"; Object[] array = new Object[]{"ZhangSan"}; String value = MessageFormat.format(message, array); System.out.println(value);
最終結(jié)果是:oh, } is a pig
關(guān)于MessageFormat.format方法:
每調(diào)用一次MessageFormat.format方法,都會新創(chuàng)建MessageFormat的一個實例,相當(dāng)于MessageFormat只使用了一次。MessageFormat類的format方法如下:
Java代碼public static String format(String pattern, Object ... arguments) { MessageFormat temp = new MessageFormat(pattern); return temp.format(arguments); }
如果要重復(fù)使用某個MessageFormat實例,可以用如下方式:
Java代碼String message = "oh, {0} is a pig"; MessageFormat messageFormat = new MessageFormat(message); Object[] array = new Object[]{"ZhangSan"}; String value = messageFormat.format(array); System.out.println(value);
最終結(jié)果是:oh, ZhangSan is a pig
在Java程序中做字符串拼接時一定要記得的MessageFormat.format
Java里從來少不了字符串拼接的活,Java程序員也肯定用到過StringBuffer,StringBuilder,以及被編譯器優(yōu)化掉的+=。但這些都和下文要談的無關(guān)。
比如有這樣的字符串:
張三將去某地點找李四。
其中,張三某地點和李四都是可變的,比如張三變成王五,某地點變成紐約,李四變成趙六。于是整句變成:
王五將去紐約找趙六。
如果直接將張三,某地點和李四用變量替代,再拼接起來,可以達到目的。但是,代碼不好寫,也不好看,也不好維護。但是,我看過很多SQL拼接,HTML拼接都是這樣做的。我自己以前也是這樣,自從接觸了MessageFormat.format之后才意識到有更好的形式。請看下面的代碼:
String[] tdArr=...; String result=MessageFormat.format("<tr bgcolor='#cef'><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>", tdArr);
這段代碼將把數(shù)組tdArr中的四個元素分別插入到{0},{1},{2},{3}的位置。
你看看,是不是這樣形式和內(nèi)容有效的分開了。容易想象,當(dāng)元素增多時,這種方式優(yōu)勢很明顯。
一件事有很多手段來達成,知道那種手段更好,是你經(jīng)驗的體現(xiàn)和專業(yè)化的特征。
補記:
如果字符串需要輸出單引號',可以用兩個單引號''進行轉(zhuǎn)義,下面代碼請參考:
public int insertToTest_tb(String createTime,String datefrom,String dateto,String name,String intranetid,String actualhour,String planhour,String status) throws Exception{ StringBuilder sb=new StringBuilder(); sb.append(" insert into test_tb ("); sb.append(" createTime, "); sb.append(" datefrom, "); sb.append(" dateto, "); sb.append(" name, "); sb.append(" intranetid, "); sb.append(" actualhour, "); sb.append(" planhour, "); sb.append(" status"); sb.append(" ) values ("); sb.append(" ''{0}'',"); sb.append(" ''{1}'',"); sb.append(" ''{2}'',"); sb.append(" ''{3}'',"); sb.append(" ''{4}'',"); sb.append(" ''{5}'',"); sb.append(" ''{6}'',"); sb.append(" ''{7}''"); sb.append(" )"); String result=sb.toString(); Object[] arr={createTime,datefrom,dateto,name,intranetid,actualhour,planhour,status}; String sql=MessageFormat.format(result, arr); return this.getJdbcTemplate().update(sql); }
新聞熱點
疑難解答