使用 DecimalFormat 和 NumberFormat 處理數字的格式化顯示問題(千分位、百分號等)

前言

在工作當中,可能經常會遇到比如數據保留兩位小數顯示,去除後面多餘0,按指定格式輸出數據這種需求,有時隔得時間久了也難免會忘記,所以就稍作總結方便今後查看,同時最後提供一個工具類方便今後使用。NumberFormat爲數值格式化的工具類,DecimalFormat 是 NumberFormat 的一個具體子類,用於格式化十進制數字。

一、NumberFormat

  • NumberFormat 是所有數值格式的抽象基類。此類提供格式化和解析數值的接口。NumberFormat 還提供了一些方法來確定哪些語言環境具有數值格式,以及它們的名稱是什麼。
  • NumberFormat 可用於格式化和解析任何語言環境的數值。使代碼能夠完全獨立於小數點、千位分隔符甚至所用特定小數位數的語言環境約定,並與數值格式是否爲偶小數無關。

數值格式化

  1. getInstance()、getNumberInstance()。返回當前默認語言環境的通用數值格式。
  2. getInstance(Locale)、getNumberInstance(Locale)。返回指定語言環境的通用數值格式。
  3. NumberFormat.setMinimumIntegerDigits(int)。設置數的整數部分所允許的最小位數。
  4. NumberFormat.setMaximumIntegerDigits(int)。設置數的整數部分所允許的最大位數。
  5. NumberFormat.setMinimumFractionDigits(int)。設置最少小數點位數,不足的位數以0補位,超出的話按實際位數輸出。
  6. 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
    }

}

貨幣格式化

  1. getCurrencyInstance()。靜態方法,建立一個NumberFormat類的對象並返回引用,該引用指定貨幣格式爲系統預設的貨幣格式。
  2. 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
    }

}

百分比格式化

  1. getPercentInstance()。靜態方法,創建一個NumberFormat類的對象並返回其引用。該對象指定百分比格式爲系統預設格式。
  2. 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章