前言
在工作當中,可能經常會遇到比如數據保留兩位小數顯示,去除後面多餘0,按指定格式輸出數據這種需求,有時隔得時間久了也難免會忘記,所以就稍作總結方便今後查看,同時最後提供一個工具類方便今後使用。NumberFormat爲數值格式化的工具類,DecimalFormat 是 NumberFormat 的一個具體子類,用於格式化十進制數字。
一、NumberFormat
- NumberFormat 是所有數值格式的抽象基類。此類提供格式化和解析數值的接口。NumberFormat 還提供了一些方法來確定哪些語言環境具有數值格式,以及它們的名稱是什麼。
- NumberFormat 可用於格式化和解析任何語言環境的數值。使代碼能夠完全獨立於小數點、千位分隔符甚至所用特定小數位數的語言環境約定,並與數值格式是否爲偶小數無關。
數值格式化
- getInstance()、getNumberInstance()。返回當前默認語言環境的通用數值格式。
- getInstance(Locale)、getNumberInstance(Locale)。返回指定語言環境的通用數值格式。
- NumberFormat.setMinimumIntegerDigits(int)。設置數的整數部分所允許的最小位數。
- NumberFormat.setMaximumIntegerDigits(int)。設置數的整數部分所允許的最大位數。
- NumberFormat.setMinimumFractionDigits(int)。設置最少小數點位數,不足的位數以0補位,超出的話按實際位數輸出。
- NumberFormat.setMaximumFractionDigits(int)。設置最多保留小數位數,不足不補0。
import java.text.NumberFormat;
import java.util.Locale;
public class HelloWorld {
public static void main(String[] args) {
numberFormat();
}
private static void numberFormat() {
double d = 12345.676688000;
NumberFormat nf = NumberFormat.getNumberInstance();
System.out.println(nf.format(d));//12,345.677 默認只保留到小數點後三位
nf.setMinimumIntegerDigits(2);
System.out.println(nf.format(d));//12,345.677 整數部分大於2位按默認最大小數位數3位輸出
d = 1234.0;
nf.setMaximumIntegerDigits(3);
System.out.println(nf.format(d));//234
nf = NumberFormat.getInstance();
d = 12345.6766;
nf.setMinimumFractionDigits(1);
System.out.println(nf.format(d));//12,345.677 小數部分大於1位,按默認最大小數位數3位輸出
nf.setMinimumFractionDigits(5);
System.out.println(nf.format(d));//12,345.67660 不夠位數補0
nf.setMaximumFractionDigits(1);
System.out.println(nf.format(d));//12,345.7
nf = NumberFormat.getNumberInstance(Locale.US);
d = 12345.6789;
System.out.println(nf.format(d));//12,345.679
nf = NumberFormat.getNumberInstance(Locale.FRANCE);
System.out.println(nf.format(d));//12 345,679
}
}
貨幣格式化
- getCurrencyInstance()。靜態方法,建立一個NumberFormat類的對象並返回引用,該引用指定貨幣格式爲系統預設的貨幣格式。
- getCurrencyInstance(Locale) 。靜態方法,建立一個NumberFormat類的對象,並返回引用,該引用的貨幣格式由Locale指定。Locale類在java.util包中。
import java.text.NumberFormat;
import java.util.Locale;
public class HelloWorld {
public static void main(String[] args) {
currencyFormat();
}
private static void currencyFormat() {
//按系統預設的貨幣格式輸出,這裏是人民幣
NumberFormat nf = NumberFormat.getCurrencyInstance();
System.out.println(nf.format(123.456));//¥123.46
//按指定的貨幣格式輸出,這裏是美元
//Locale locale = Locale.US;
nf = NumberFormat.getCurrencyInstance(Locale.US);
System.out.println(nf.format(123.456));//$123.46
}
}
百分比格式化
- getPercentInstance()。靜態方法,創建一個NumberFormat類的對象並返回其引用。該對象指定百分比格式爲系統預設格式。
- getPercentInstance(Locale)。靜態方法,創建一個NumberFormat類的對象並返回引用。該對象的百分比格式由Locale來指定。
private static void percentFormat() {
//按系統預設百分比格式輸出
double d = 123.456;
NumberFormat nf = NumberFormat.getPercentInstance();
System.out.println(nf.format(d));//12,346%
//按指定百分比格式輸出,這裏是法國格式
nf = NumberFormat.getPercentInstance(Locale.FRANCE);
System.out.println(nf.format(d));//12 346 %
}
工具類
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class NumberDealUtil {
/**
* 移除數字前面和後面冗餘的0,只保留3位小數
*
* @param isFormat 是否需要千位分隔符(,)這種格式輸出
* @param num
* @return
*/
public static String trim0(boolean isFormat, double num) {
NumberFormat nf = NumberFormat.getInstance();
if (!isFormat) {
//設置輸出格式是否使用“,”分組,默認是使用的
nf.setGroupingUsed(false);
}
String result = nf.format(num);
// return isFormat ? result : result.replace(",", ""); //用上面代碼替換去除分隔符操作
return result;
}
/**
* 移除數字前面和後面冗餘的0
*
* @param isFormat 是否需要千位分隔符(,)這種格式輸出
* @param num
* @param fractionDigit 要保留的小數位數
* @return
*/
public static String trim0(boolean isFormat, double num, int fractionDigit) {
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(fractionDigit);
//setMaximumFractionDigits不會保留小數點和後面多餘的0,不需下面正則去除
// if (result.contains(".") && result.endsWith("0")) {
// result = result.replaceAll("0+?$", "");//去掉多餘的0
// result = result.replaceAll("[.]$", "");//如最後一位是.則去掉
// }
if (!isFormat) {
//設置輸出格式是否使用“,”分組,默認是使用的
nf.setGroupingUsed(false);
}
String result = nf.format(num);
// return isFormat ? result : result.replace(",", "");
return result;
}
/**
* 指定位數輸出,不足補0
* 整數部分如果位數大於需要的位數按實際位數輸出
* 小數部分如果大於需要的位數四捨五入
*
* @param num
* @param integerDigit 整數部分位數
* @param fractionDigit 小數部分位數
* @return
*/
public static String add0Format(double num, int integerDigit, int fractionDigit) {
StringBuilder rule = new StringBuilder();
if (integerDigit <= 0) {
rule.append("#");
} else {
for (int i = 0; i < integerDigit; i++) {
rule.append("0");
}
}
if (fractionDigit > 0) {
rule.append(".");
for (int i = 0; i < fractionDigit; i++) {
rule.append("0");
}
}
DecimalFormat df = new DecimalFormat(rule.toString());
return df.format(num);
}
/**
* 保留幾位小數,不足不補0,小數部分冗餘的0也不顯示
*
* @param num
* @param fractionDigit 要保留小數的位數
* @return
*/
public static String fractionDigitFormat(double num, int fractionDigit) {
/*方法一*/
// StringBuilder rule = new StringBuilder("#");
// if (fractionDigit > 0) {
// rule.append(".");
// for (int i = 0; i < fractionDigit; i++) {
// rule.append("#");
// }
// }
// DecimalFormat df = new DecimalFormat(rule.toString());
// return df.format(num);
/*方法二*/
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(fractionDigit);
//設置輸出格式是否使用“,”分組,這裏不使用
nf.setGroupingUsed(false);
return nf.format(num);
}
}
二、DecimalFormat
符號含義:
符號 | 位置 | 本地化 | 含義 |
---|---|---|---|
0 | 數字 | 是 | 阿拉伯數字 |
# | 數字 | 是 | 阿拉伯數字如果不存在就顯示爲空 |
. | 數字 | 是 | 小數分隔符或貨幣小數分隔符 |
- | 數字 | 是 | 減號 |
, | 數字 | 是 | 分組分隔符 |
E | 數字 | 是 | 分割科學技術法中的尾數和指數。在前綴和後綴中無需添加引號 |
; | 子模式邊界 | 是 | 分隔正數和負數子模式 |
% | 前綴或後綴 | 是 | 乘以100並顯示爲百分數 |
/u2030 | 前綴或後綴 | 是 | 乘以1000並顯示爲千分數 |
¤ (\u00A4) | 前綴或後綴 | 否 | 貨幣記號,由貨幣符號替換。如果兩個同時出現,則用國際貨幣符號替換。如果出現在某個模式中,則使用貨幣小數分隔符,而不使用小數分隔符 |
' | 前綴或後綴 | 否 | 用於在前綴或或後綴中爲特殊字符加引號,例如 "'#'#" 將 123 格式化爲 "#123"。要創建單引號本身,請連續使用兩個單引號:"# o''clock" |
分析問題和實戰
當真的要寫實戰分析的時候發現真的不知道怎麼寫了,尷尬了啊!
先來說一下最常用的寫法。
1.最基本的使用
1.1 0和#配合使用
網上的例子還是比較多的,我也感覺很有代表性,我也借鑑一下。下面直接上代碼:
double pi = 3.1415927;//圓周率
//取一位整數
System.out.println(new DecimalFormat("0").format(pi));//3
//取一位整數和兩位小數
System.out.println(new DecimalFormat("0.00").format(pi));//3.14
//取兩位整數和三位小數,整數不足部分以0填補。
System.out.println(new DecimalFormat("00.000").format(pi));// 03.142
//取所有整數部分
System.out.println(new DecimalFormat("#").format(pi));//3
//以百分比方式計數,並取兩位小數
System.out.println(new DecimalFormat("#.##%").format(pi));//314.16%
/**
* 上面的代碼就是網上很經典的案例,下面我們來分析另外的一個值
*/
pi=12.34567;
//取一位整數
System.out.println(new DecimalFormat("0").format(pi));//12
//取一位整數和兩位小數
System.out.println(new DecimalFormat("0.00").format(pi));//12.35
//取兩位整數和三位小數,整數不足部分以0填補。
System.out.println(new DecimalFormat("00.000").format(pi));// 12.346
//取所有整數部分
System.out.println(new DecimalFormat("#").format(pi));//12
//以百分比方式計數,並取兩位小數
System.out.println(new DecimalFormat("#.##%").format(pi));//1234.57%
/**
* 擴展,如果是其他的數字會是下面的效果
*/
pi=12.34;
//整數
System.out.println(new DecimalFormat("6").format(pi));//612
System.out.println(new DecimalFormat("60").format(pi));//612
System.out.println(new DecimalFormat("06").format(pi));//126
System.out.println(new DecimalFormat("00600").format(pi));//00126
System.out.println(new DecimalFormat("#####60000").format(pi));//00126
//小數
System.out.println(new DecimalFormat(".6").format(pi));//12.6
System.out.println(new DecimalFormat(".06").format(pi));//12.36
System.out.println(new DecimalFormat(".60").format(pi));//12.36
System.out.println(new DecimalFormat(".0600").format(pi));//12.3406
System.out.println(new DecimalFormat(".6000").format(pi));//12.3406
System.out.println(new DecimalFormat(".600000##").format(pi));//12.340006
上面的例子基本滿足我們想要的格式化的一些東西了。我們來對比分析一下上面兩個值,很明顯.
就是我們常用的小數點分隔符,前面是整數,後面是小數。
1.整數:若是n個0,就從個位開始向高位填充,如果有值就是原來的值,沒有就填充0。
若都是#,沒有實際意義,不管是幾個#,最後的結果都是原來的整數。
0和#配合使用,只能是"##00",不能是"00##",就是#在前0在後
。實現是上面的合集。
2.小數:是可以保留小數點後幾位的(幾個0後或幾個#)。
若n個0,就是保留n位小數,小數不足的部分用0填充。
若n個#,就是保留n位小數,小數不足部分沒有就是沒有。
0和#配合使用,只能是".00##",不能是".##00",就是0在前#在後
。實現和上面一樣。
3.數字(1-9):上面的分析不是#就是0,如果是其他的數值會怎樣呢?
上面的擴展很詳細的說明這個問題。
整數:若沒有0或#,默認在後面拼接整數;若有0或#,找到第一個0或#的位置,然後找出所有的0或#拼在一起,按照上面的規則,在第一個0或#出現的位置插入響應的格式化以後的值。
小數:若沒有0或#,格式化是什麼就顯示什麼;若有0或#,找出所有的0或#拼在一起,按照上面的規則,在小數點的後面插入響應的格式化以後的值。
有了上面的總結,想生成什麼就是什麼,就是這麼人性!
2.科學計數法 E
在使用double的時候如果後面的小數爲過多就會自動轉換爲科學計數法,你聽聽這名字多麼高級,科學計數法。(這一塊寫的我心力憔悴😯)
來吧我們直接上代碼然後分析:
pi = 123456789.3456;
System.out.println(new DecimalFormat("0E0").format(pi));//1E8
System.out.println(new DecimalFormat("0E00").format(pi));//1E08
System.out.println(new DecimalFormat("#E0").format(pi));//.1E9
System.out.println(new DecimalFormat("##E0").format(pi));//1.2E8
System.out.println(new DecimalFormat("###E0").format(pi));//123E6
System.out.println(new DecimalFormat("####E0").format(pi));//1.235E8
System.out.println(new DecimalFormat("#####E0").format(pi));//1234.6E5
System.out.println(new DecimalFormat("######E0").format(pi));//123.457E6
System.out.println(new DecimalFormat("#######E0").format(pi));//12.34568E7
System.out.println(new DecimalFormat("########E0").format(pi));//1.2345679E8
System.out.println(new DecimalFormat("#########E0").format(pi));//123456789E0
System.out.println(new DecimalFormat("##########E0").format(pi));//123456789.3E0
pi = 12345678.3456;
System.out.println(new DecimalFormat("0E0").format(pi));//1E7
System.out.println(new DecimalFormat("0E00").format(pi));//1E07
System.out.println(new DecimalFormat("#E0").format(pi));//.1E8
System.out.println(new DecimalFormat("##E0").format(pi));//12E6
System.out.println(new DecimalFormat("###E0").format(pi));//12.3E6
System.out.println(new DecimalFormat("####E0").format(pi));//1235E4
System.out.println(new DecimalFormat("#####E0").format(pi));//123.46E5
System.out.println(new DecimalFormat("######E0").format(pi));//12.3457E6
System.out.println(new DecimalFormat("#######E0").format(pi));//12.34568E7
System.out.println(new DecimalFormat("########E0").format(pi));//12345678E0
System.out.println(new DecimalFormat("#########E0").format(pi));//12345678.3E0
System.out.println(new DecimalFormat("##########E0").format(pi));//12345678.35E0
/**
* 0的個數決定最後輸出結果的位數
* 並且與0的位置無關
*/
pi = 12345;
System.out.println(new DecimalFormat("###.##E0").format(pi));//12.345E3
System.out.println(new DecimalFormat("##0.##E0").format(pi));//12.345E3
System.out.println(new DecimalFormat("##0.0##E0").format(pi));//12.345E3
System.out.println(new DecimalFormat("##0.00000##E0").format(pi));//12.3450E3
System.out.println(new DecimalFormat("#00.0000##E0").format(pi));//12.3450E3
System.out.println(new DecimalFormat("#00.00000##E0").format(pi));//12.34500E3
上面的例子我感覺還是比較全的,看看例子分析一下,就能明白了。
總結:
1.使用科學計數法,首先保證E
前面有0或者#,否則就不是科學計數法。
2.E
後面必須是0,0的個數對後面的顯示是有影響的,多餘就會填充0.
3.E
前面只有一個#,得到的結果肯定是.
開頭的結果。
4.E
前面#與0的總個數決定後面的指數,具體:總個數和指數比較,如果指數的值大於總個數,那麼得到的指數的值是個數的倍數;如果指數的值小於等於總個數,那麼得到的指數的值等於總個數;
5.整個模式中的0的總個數決定最後輸出結果的位數,並且與0的位置無關。
6.如果整數部分需要保留幾位數,就使用幾個0。
3.分組分隔符和減號
3.1分組分隔符 ,
這不就是逗號麼?不這是分隔符,哈哈😄!
直接上代碼:
pi = 1299792458;
//每三位以逗號進行分隔。
System.out.println(new DecimalFormat(",###").format(pi));//1,299,792,458
System.out.println(new DecimalFormat(",##").format(pi));//12,99,79,24,58
System.out.println(new DecimalFormat("###,##").format(pi));//12,99,79,24,58
上面的代碼,最常用的就是千位分隔符。
不管模式中有多少個分隔符,最右邊的那一個有效;每一組的個數就是最右邊的分隔符之右的整數位數。
3.2 減號 -
-
表示輸出爲負數, 要放在最前面。代碼如下:
pi = 3.14;
System.out.println(new DecimalFormat("-0.00").format(pi));//-3.14
4. 關於前綴、後綴
4.1 % 將數字乘以100
pi = 0.1234;
System.out.println(new DecimalFormat("0.00%").format(pi));//12.34%
System.out.println(new DecimalFormat("0%.00").format(pi));//12.34%
System.out.println(new DecimalFormat("%0.00").format(pi));//%12.34
%處理最前面不能放置之外,其他的地方都可以放置。
4.2 \u2030 將數字乘以1000
pi = 0.1234;
System.out.println(new DecimalFormat("0.00\u2030").format(pi));//123.40‰
System.out.println(new DecimalFormat("0.0\u20300").format(pi));//123.40‰
System.out.println(new DecimalFormat("\u20300.00").format(pi));//‰123.40
\u2030
和%
用法是一樣的。
4.3 ¤(\u00A4) 本地化貨幣符號
如果連續出現兩次,代表貨幣符號的國際代號。
pi = 1234.5678;
System.out.println(new DecimalFormat(",000.00¤").format(pi));//1,234.57¥
System.out.println(new DecimalFormat(",000.¤00").format(pi));//1,234.57¥
System.out.println(new DecimalFormat("¤,000.00").format(pi));//¥1,234.57
System.out.println(new DecimalFormat(",00¤0.¤00").format(pi));//1,234.57¥¥
System.out.println(new DecimalFormat("¤,000.¤00").format(pi));//¥1,234.57¥
System.out.println(new DecimalFormat(",000.00¤¤").format(pi));//1,234.57CNY
4.4 ' 用於引用特殊的字符,作爲前綴或後綴。
pi = 4.5678;
System.out.println(new DecimalFormat("'#'0.00").format(pi));//#4.57
System.out.println(new DecimalFormat("'^ _ ^'0.00").format(pi));//^ _ ^4.57
//使用'本身作爲前綴或後綴
System.out.println(new DecimalFormat("''0.00").format(pi));//'4.57
5. 四捨五入
說的就是我們數學上常說的四捨五入的問題。
DecimalFormat
提供 RoundingMode
中定義的舍入模式進行格式化。默認情況下,它使用 RoundingMode.HALF_EVEN
。
6. 同步
DecimalFormat 通常不是同步的。建議爲每個線程創建獨立的格式實例。如果多個線程同時訪問某個格式,則必須保持外部同步。
7. 特殊值
NaN 被格式化爲一個字符串,通常具有單個字符 \uFFFD。此字符串由 DecimalFormatSymbols 對象所確定。這是唯一不使用前綴和後綴的值。
無窮大的值被格式化爲一個字符串,通常具有單個字符 \u221E,具有正數或負數前綴和後綴。無窮大值的字符串由 DecimalFormatSymbols 對象所確定。
將負零("-0")解析爲
- 如果 isParseBigDecimal() 爲 true,則爲 BigDecimal(0),
- 如果 isParseBigDecimal() 爲 false 並且 isParseIntegerOnly() 爲 true,則爲 Long(0),
- 如果 isParseBigDecimal() 和 isParseIntegerOnly() 均爲 false,則爲 Double(-0.0)。
參考博客:
https://www.jianshu.com/p/b3699d73142e
https://www.jianshu.com/p/b9dd363e3ff8