前面介紹了字符串變量的四種賦值方式,對於簡單的賦值來講徹底夠用了,即使是兩個字符串拼接,也只需經過加號把兩個目標串連起來便可。但對於複雜的賦值來講就麻煩了,假設如今須要拼接一個很長的字符串,字符串內部包含了各類類型的變量,有整型,有雙精度型,有布爾型,有字符型,中間還夾雜着一些起粘合做用的子串,如此一來只能使勁地填寫加號,把各類變量努力加加加加上去,就像有時打印日誌調用System.out.println就很是痛苦,加號多到讓你眼花繚亂。
爲了避免讓加號如此橫行霸道,String類型從Java5開始,額外提供了format方法對填入字符串的各類變量進行格式化。具體地說,是在一個模板字符串中填寫相似「%s」、「%d」、「%f」這樣的記號先佔幾個位置,而後給format方法的輸入參數分別指定對應位置的變量名稱,表示這些變量值依次替換模板中的「%s」、「%d」、「%f」等等記號。以上模板串用到的佔位記號也叫作格式轉換符,分別說明以下:
%s : 這是字符串的佔位記號,可原樣展現字符串如"Hello"。
%c : 這是字符的佔位記號,可原樣展現字符如'A'。
%b : 這是布爾值的佔位記號,可原樣展現true或者false。
%d : 這是十進制整數(含字節型、短整型、整型、長整型)的佔位記號,可原樣展現十進制數如255。
%o : 這是八進制整數的佔位記號,填寫十進制數,格式化後會轉換成八進制數。例如,輸入整數255會輸出八進制數377。
%x : 這是十六進制整數的佔位記號,填寫十進制數,格式化後會轉換成十六進制數。例如,輸入整數255會輸出十六進制數ff。
%f : 這是浮點數的佔位記號,格式化後會轉換成七位小數(整數部分與小數部分加起來)。
下面是利用format方法格式化單個變量值與多個變量值的代碼例子:html
// 往字符串填入另外一個字符串 String fromString = String.format("格式化子串的字符串:%s", "Hello"); System.out.println("fromString="+fromString); // 往字符串填入字符 String fromChar = String.format("格式化字符的字符串:%s", 'A'); System.out.println("fromChar="+fromChar); // 往字符串填入布爾值 String fromBoolean = String.format("格式化布爾值的字符串:%b", false); System.out.println("fromBoolean="+fromBoolean); // 往字符串填入十進制整數 String fromInt = String.format("格式化整型數的字符串:%d", 255); System.out.println("fromInt="+fromInt); // 往字符串填入十六進制數 String fromOct = String.format("格式化十六進制數的字符串:%o", 255); System.out.println("fromOct="+fromOct); // 往字符串填入八進制數 String fromHex = String.format("格式化八進制數的字符串:%x", 255); System.out.println("fromHex="+fromHex); // 往字符串填入浮點數 String fromFloat = String.format("格式化浮點數的字符串:%f", 3.14); System.out.println("fromFloat="+fromFloat); // 格式化字符串的時候,同時填充多個變量 String manyVariable = String.format("如下字符串包括了多個變量值:%s,%c,%b,%d,%o,%x,%f", "Hello", 'A', false, 255, 255, 255, 3.14); System.out.println("manyVariable="+manyVariable);
觀察上面的代碼,可見大部分的基本類型都支持格式化,除了雙精度型。若是雙精度數的精度恰好在浮點數範圍以內,還能借助標記%f來格式化,要是雙精度數超過了浮點數的精度,還能使用%f格式化嗎?接下來經過如下的測試代碼,看看3.1415926這個雙精度數會被%f格式化成什麼樣子:java
// 注意,雙精度數如果經過%f格式化雙精度數,則會強制轉成浮點數 String fromDouble = String.format("雙精度數格式化後丟失精度的字符串:%f", 3.1415926); System.out.println("fromDouble="+fromDouble);
運行以上的測試代碼,打印的日誌結果以下所示:git
fromDouble=雙精度數格式化後丟失精度的字符串:3.141593
可見使用%f格式化雙精度數,超出範圍的小數部分被強行四捨五入了,於是%f並不適合用於直接格式化雙精度型。若想讓雙精度數在格式化時不損失精度,須要程序員指定小數點後面的保留位數,好比%.8f表示格式化時保留八位小數部分,f前面的數字越大表明保留的位數越多,雙精度數的數值精度就越高。利用%.8f改寫以前的雙精度數格式化代碼,改寫後的演示代碼以下:程序員
// 所以,格式化雙精度數之時,須要指定小數點後面的保留位數 String fromDecimal = String.format("格式化雙精度數的字符串:%.8f", 3.1415926); System.out.println("fromDecimal="+fromDecimal);
運行如上的演示代碼,程序運行結果以下所示:測試
fromDecimal=格式化雙精度數的字符串:3.14159260
從日誌信息可見,此時雙精度數的小數部分得以完整地保存了下來。編碼
所謂的格式化,不僅僅是按照標記填寫具體數值,還要求字符串格式整齊劃一。譬如統計世界各國人口,列表中的各國人口數值應當右對齊,這樣誰多誰少方能一目瞭然。既然要求支持對齊,那麼得先明確該列數字的最大位數,以後才能在位數範圍內選擇左對齊仍是右對齊。整數部分最大位數的標記方式與小數部分的保留位數相似,惟一的區別是整數位數的標記不加點號,而小數位數的標記要加點號,例如%8d表示待格式化的整數將佔據八個字符空間,而且默認右對齊、左補空格。假若要求左對齊,則格式化標記需添加符號,像%-8d表示待格式化的整數在八位空間內左對齊,而且右補空格。有時候數字表明一串編碼,即便未達到最大位數也得在左邊補0,此時格式化標記要在位數前面補充0,表明空出來的位置填0而不是填空格,如標記%08d表示待格式化的整數要求右對齊、左補0。下面是對整數位數進行各類格式化的代碼例子:設計
// 對整數分配固定長度,該整數默認右對齊、左補空格 String fromLenth = String.format("格式化固定長度(默認右對齊)的整數字符串:(%8d)", 255); System.out.println("fromLenth="+fromLenth); // 對整數分配固定長度,且該整數左對齊、右補空格 String fromLeft = String.format("格式化固定長度且左對齊的整數字符串:(%-8d)", 255); System.out.println("fromLeft="+fromLeft); // 對整數分配固定長度,該整數默認右對齊、左補0 String fromZero = String.format("格式化固定長度且左補0的整數字符串:(%08d)", 255); System.out.println("fromZero="+fromZero);
運行上述的格式化代碼,獲得下列的日誌打印結果:日誌
fromLenth=格式化固定長度(默認右對齊)的整數字符串:( 255) fromLeft=格式化固定長度且左對齊的整數字符串:(255 ) fromZero=格式化固定長度且左補0的整數字符串:(00000255)
因而可知,格式化後的數字既實現了右對齊,也實現了左對齊,還支持在空位補0。orm
一旦格式化用得多了,便會出現某個變量須要屢次填入的狀況,好比說「重要的事情說三遍」,後面的句子就得輸入三次,像如下代碼所示的那樣,「別遲到」三字反覆寫了三次:htm
// 字符串格式化的時候,可能出現某個變量被屢次填入的狀況 String fromRepeat1 = String.format("重要的事情說三遍:%s,%s,%s", "別遲到", "別遲到", "別遲到"); System.out.println("fromRepeat1="+fromRepeat1);
這種作法無疑很是拖沓,不但寫起來費勁,看起來也費神。爲此格式化又設計了形如「%n$s」的標記,其中n表示當前標記取的是第幾個參數值,尾巴的s就是普通的格式化標記,中間的美圓符號$把二者隔開。例如標記%1$s表示當前要取第一個參數,且該參數類型爲字符串,因而前述的「重要的事情說三遍」便可簡化爲如下代碼:
// 重複填入某個變量值,可利用「%數字$」的形式,其中「數字$」表示這裏取後面的第幾個變量值 String fromRepeat2 = String.format("重要的事情說三遍:%1$s,%1$s,%1$s", "別遲到"); System.out.println("fromRepeat2="+fromRepeat2);
如今有個比較常見的業務要求,金額數字一般都要保留小數點後面兩位,像餘額寶的每日收益就精確到小數點後兩位的單位分。此時採起標記%.2f便可實現要求,可是餘額寶內部對帳可不能僅僅保留兩位小數,通常至少保留小數點後三位的單位釐,那麼對帳用的格式化標記就變成了%.3f。這樣有的場合要求更高精度,有的場合精度要求不高,意味着標記%.nf中間的n值是隨時變化着的。若要處理變化的輸入數值,必須經過方法實現相關功能,也就是須要設計一個新方法,該方法的輸入參數包括待格式化的數字,以及須要保留的小數位數,方法的返回值爲截取指定小數位的字符串。
對於雙精度數字來講,此時要先根據小數位數構建一個形如%.nf的格式化標記串,再依據該標記格式化最終的數值字符串。因爲百分號%是格式化的保留字符,所以要用兩個百分號%%來表達一個百分符號%,因而雙精度數的小數位數格式化代碼書寫以下:
// 對雙精度類型的變量截取小數位,多餘部分的數字默認四捨五入 public static String formatWithDouble(double value, int digit) { // 先根據小數位數構建格式化標記串。兩個百分號%%可轉義爲一個百分符號% String format = String.format("%%.%df", digit); // 再依據該標記對具體數字進行字符串格式化 String result = String.format(format, value); return result; }
對於大小數類型而言,BigDecimal提供了專門的setScale方法,該方法不但容許指定截取的小數位,還支持設置特定的舍入規則,固然一般狀況使用RoundingMode.HALF_UP表明四捨五入便可。下面即是截取大小數的方法代碼例子:
// 對大小數類型的變量截取小數位,可指定多餘部分數字的舍入規則 public static String formatWithBigDecimal(BigDecimal value, int digit) { // 大小數類型的setScale方法須要指定明確的舍入規則,其中HALF_UP表示四捨五入 BigDecimal result = value.setScale(digit, RoundingMode.HALF_UP); return result.toString(); }
接下來外部分別調用上面的雙精度數格式化方法formatWithDouble,以及大小數格式化方法formatWithBigDecimal,具體的測試調用代碼以下所示:
double normalDecimal = 19.895; // 保留雙精度數的小數點後面兩位 String normalResult = formatWithDouble(normalDecimal, 2); System.out.println("normalResult="+normalResult); BigDecimal bigDecimal = new BigDecimal("123456789012345678.901"); // 保留大小數的小數點後面兩位 String bigResult = formatWithBigDecimal(bigDecimal, 2); System.out.println("bigResult="+bigResult);
運行上述的精度格式化代碼,輸出如下的日誌打印信息:
normalResult=19.90 bigResult=123456789012345678.90
可見不論是雙精度格式化,仍是大小數格式化,都實現了四捨五入保留兩位小數的目標。
更多Java技術文章參見《Java開發筆記(序)章節目錄》