Java中的BigDecimal使用問(wèn)題小結(jié)
這篇文章讓我來(lái)詳細(xì)講解 Java 中的 BigDecimal 類,包括它的用途、適用場(chǎng)景、以及潛在問(wèn)題。
一、 BigDecimal 是什么?
BigDecimal
是 Java 中用于表示任意精度的十進(jìn)制數(shù)的類。它解決了 float
和 double
在進(jìn)行精確計(jì)算時(shí)可能出現(xiàn)的精度丟失問(wèn)題。BigDecimal
類提供了對(duì)數(shù)字進(jìn)行加、減、乘、除等運(yùn)算的方法,并且可以控制舍入模式。
二、 為什么需要 BigDecimal?
float
和 double
類型是基于二進(jìn)制的浮點(diǎn)數(shù)表示,它們無(wú)法精確地表示某些十進(jìn)制數(shù)(例如 0.1)。這會(huì)導(dǎo)致在進(jìn)行涉及貨幣、金融等需要精確計(jì)算的場(chǎng)景時(shí)出現(xiàn)誤差。
例如:
double a = 0.1; double b = 0.2; double sum = a + b; System.out.println(sum); // 輸出:0.30000000000000004 ??
可以看到,0.1 + 0.2
的結(jié)果并不是精確的 0.3
。 而BigDecimal
可以避免這種問(wèn)題。?
三、 BigDecimal 的使用場(chǎng)景
- 金融計(jì)算: 貨幣計(jì)算、利率計(jì)算、稅收計(jì)算等,任何需要精確到小數(shù)點(diǎn)后幾位的計(jì)算。
- ??科學(xué)計(jì)算: 需要高精度計(jì)算的科學(xué)領(lǐng)域,例如物理、化學(xué)等。
- ??商業(yè)應(yīng)用: 訂單金額計(jì)算、庫(kù)存管理、報(bào)表生成等。
- ??任何需要避免浮點(diǎn)數(shù)精度問(wèn)題的場(chǎng)景。 ??
BigDecimal
的用法
創(chuàng)建 BigDecimal
對(duì)象:
- BigDecimal(String val):推薦使用字符串構(gòu)造方法,避免 double 帶來(lái)的精度問(wèn)題。 ??
- BigDecimal(int val)
- BigDecimal(long val)
- BigDecimal(double val):不推薦,因?yàn)?double 本身就可能存在精度問(wèn)題。 ??
- BigDecimal.valueOf(double val):底層也是將 double 轉(zhuǎn)換為字符串,然后創(chuàng)建 BigDecimal 對(duì)象,比直接使用 BigDecimal(double) 更好。 ??
- BigDecimal num1 = new BigDecimal("0.1"); // 推薦
- BigDecimal num2 = new BigDecimal(0.1); // 不推薦
- BigDecimal num3 = BigDecimal.valueOf(0.1); // 推薦
BigDecimal num1 = new BigDecimal("0.1"); // 推薦 BigDecimal num2 = new BigDecimal(0.1); // 不推薦 BigDecimal num3 = BigDecimal.valueOf(0.1); // 推薦
常用方法:
- add(BigDecimal augend):加法
- subtract(BigDecimal subtrahend):減法
- multiply(BigDecimal multiplicand):乘法
- divide(BigDecimal divisor):除法
- divide(BigDecimal divisor, int scale, RoundingMode roundingMode):除法,指定精度和舍入模式。
- setScale(int newScale, RoundingMode roundingMode):設(shè)置精度和舍入模式。
- compareTo(BigDecimal val):比較大?。ǚ祷?-1, 0, 1,分別表示小于、等于、大于)
- toString():轉(zhuǎn)換為字符串
- intValue(), longValue(), floatValue(), doubleValue():轉(zhuǎn)換為基本數(shù)據(jù)類型(可能丟失精度) ??
舍入模式(RoundingMode
):
- RoundingMode.UP:遠(yuǎn)離零方向舍入。
- RoundingMode.DOWN:趨向零方向舍入。
- RoundingMode.CEILING:趨向正無(wú)窮方向舍入。
- RoundingMode.FLOOR:趨向負(fù)無(wú)窮方向舍入。
- RoundingMode.HALF_UP:四舍五入(大于等于 0.5 進(jìn)位)。
- RoundingMode.HALF_DOWN:五舍六入(大于 0.5 進(jìn)位)。
- RoundingMode.HALF_EVEN:銀行家舍入法(四舍六入,五看前一位,偶數(shù)舍去,奇數(shù)進(jìn)位)。
- RoundingMode.UNNECESSARY:斷言不需要舍入,如果需要舍入則拋出 ArithmeticException。
示例代碼
import java.math.BigDecimal; import java.math.RoundingMode; public class BigDecimalExample { public static void main(String[] args) { BigDecimal num1 = new BigDecimal("10.5"); BigDecimal num2 = new BigDecimal("3.2"); // 加法 BigDecimal sum = num1.add(num2); System.out.println("Sum: " + sum); // 減法 BigDecimal difference = num1.subtract(num2); System.out.println("Difference: " + difference); // 乘法 BigDecimal product = num1.multiply(num2); System.out.println("Product: " + product); // 除法 (需要指定精度和舍入模式) try { BigDecimal quotient = num1.divide(num2, 2, RoundingMode.HALF_UP); // 保留兩位小數(shù),四舍五入 System.out.println("Quotient: " + quotient); } catch (ArithmeticException e) { System.out.println("除法運(yùn)算出錯(cuò):" + e.getMessage()); } // 設(shè)置精度 BigDecimal scaledNum = num1.setScale(1, RoundingMode.HALF_UP); // 保留一位小數(shù),四舍五入 System.out.println("Scaled Number: " + scaledNum); // 比較大小 int comparisonResult = num1.compareTo(num2); if (comparisonResult > 0) { System.out.println("num1 is greater than num2"); } else if (comparisonResult < 0) { System.out.println("num1 is less than num2"); } else { System.out.println("num1 is equal to num2"); } } }
四、 BigDecimal 的潛在問(wèn)題和注意事項(xiàng)
- 性能問(wèn)題:
BigDecimal
的運(yùn)算比float
和double
慢得多。 ?? 因?yàn)樗枰M(jìn)行復(fù)雜的計(jì)算來(lái)保證精度。 因此,只有在需要精確計(jì)算的場(chǎng)景下才應(yīng)該使用BigDecimal
。 - 不可變性:
BigDecimal
對(duì)象是不可變的。 這意味著每次運(yùn)算都會(huì)創(chuàng)建一個(gè)新的BigDecimal
對(duì)象。 因此,在循環(huán)中進(jìn)行大量的BigDecimal
運(yùn)算可能會(huì)導(dǎo)致性能問(wèn)題和內(nèi)存占用過(guò)高。 ??
BigDecimal total = BigDecimal.ZERO; for (int i = 0; i < 1000; i++) { total = total.add(new BigDecimal("0.1")); // 每次循環(huán)都創(chuàng)建新的 BigDecimal 對(duì)象 } System.out.println(total);
如果需要進(jìn)行大量的 BigDecimal
運(yùn)算,可以考慮使用 BigDecimal
的 MathContext
來(lái)控制精度和舍入模式,或者使用其他優(yōu)化技巧。
NullPointerException
:BigDecimal
對(duì)象可以為null
。 在使用BigDecimal
對(duì)象之前,應(yīng)該先進(jìn)行判空檢查,避免NullPointerException
。 ??- 除法運(yùn)算: 在進(jìn)行除法運(yùn)算時(shí),必須指定精度和舍入模式,否則可能會(huì)拋出
ArithmeticException
(如果結(jié)果是無(wú)限循環(huán)小數(shù))。 ? - 構(gòu)造方法選擇: 始終使用
BigDecimal(String)
或BigDecimal.valueOf(double)
構(gòu)造方法,避免double
帶來(lái)的精度問(wèn)題。 ?? - 比較大小: 使用
compareTo()
方法進(jìn)行比較,不要使用==
。==
比較的是對(duì)象的引用,而不是值。 ?? - 緩存 BigDecimal 對(duì)象: 對(duì)于一些常用的 BigDecimal 值(例如 0, 1, 10),可以考慮使用靜態(tài)常量來(lái)緩存這些對(duì)象,避免重復(fù)創(chuàng)建。 ??
public static final BigDecimal ZERO = BigDecimal.valueOf(0); public static final BigDecimal ONE = BigDecimal.valueOf(1); public static final BigDecimal TEN = BigDecimal.valueOf(10);
五、 總結(jié)
BigDecimal
是 Java 中用于進(jìn)行精確十進(jìn)制計(jì)算的重要類。 它適用于金融、科學(xué)等需要高精度計(jì)算的場(chǎng)景。 但是,BigDecimal
的運(yùn)算速度較慢,并且需要注意一些潛在的問(wèn)題,例如精度、舍入模式、NullPointerException
等。 在選擇使用 BigDecimal
時(shí),需要權(quán)衡精度和性能,并根據(jù)實(shí)際情況選擇合適的構(gòu)造方法、運(yùn)算方法和舍入模式。 ??
希望這篇文章能夠幫助你更好地理解和使用 BigDecimal
類。 ??
到此這篇關(guān)于Java中的BigDecimal使用問(wèn)題小結(jié)的文章就介紹到這了,更多相關(guān)Java BigDecimal內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中處理金額計(jì)算之使用Long還是BigDecimal詳解
- java中BigDecimal的介紹及使用教程BigDecimal格式化及BigDecimal常見問(wèn)題
- Java使用BigDecimal公式精確計(jì)算及精度丟失問(wèn)題
- Java BigDecimal使用方法詳解
- java開發(fā)使用BigDecimal避坑四則
- Java?BigDecimal類的一般使用、BigDecimal轉(zhuǎn)double方式
- Java中BigDecimal類的add()的使用詳解
- Java Bigdecimal使用原理詳解
- Java中BigDecimal類與int、Integer使用總結(jié)
- Java中BigDecimal的加減乘除、比較大小與使用注意事項(xiàng)
相關(guān)文章
SpringBoot中處理的轉(zhuǎn)發(fā)與重定向方式
這篇文章主要介紹了SpringBoot中處理的轉(zhuǎn)發(fā)與重定向方式,分別就轉(zhuǎn)發(fā)和重定向做了概念解說(shuō),結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11詳解Java基礎(chǔ)篇--面向?qū)ο?(構(gòu)造方法,static、this關(guān)鍵字)
這篇文章主要介紹了Java基礎(chǔ)篇--面向?qū)ο?(構(gòu)造方法,static、this關(guān)鍵字),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04解決SpringCloud下spring-boot-maven-plugin插件的打包問(wèn)題
這篇文章主要介紹了SpringCloud下spring-boot-maven-plugin插件的打包問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03java中線程池最實(shí)用的創(chuàng)建與關(guān)閉指南
試中經(jīng)常會(huì)問(wèn)到,創(chuàng)建一個(gè)線程池需要哪些參數(shù)啊,線程池的工作原理啊,卻很少會(huì)問(wèn)到線程池如何安全關(guān)閉的,下面這篇文章主要給大家介紹了關(guān)于java中線程池最實(shí)用的創(chuàng)建與關(guān)閉的相關(guān)資料,需要的朋友可以參考下2021-09-09Java Iterator迭代器與foreach循環(huán)代碼解析
這篇文章主要介紹了Java-Iterator迭代器與foreach循環(huán),主要包括Iterator迭代器接口的操作方法和foreach 循環(huán)語(yǔ)法解析,需要的朋友可以參考下2022-04-04mysql數(shù)據(jù)庫(kù)忘記密碼時(shí)如何修改
本文主要介紹了mysql數(shù)據(jù)庫(kù)忘記密碼時(shí)如何修改的步驟方法,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02出現(xiàn)SLF4J:?Failed?to?load?class?“org.slf4j.impl.StaticLog
本文主要介紹了出現(xiàn)SLF4J:?Failed?to?load?class?“org.slf4j.impl.StaticLoggerBinder“.的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07SpringBoot淺析緩存機(jī)制之Redis單機(jī)緩存應(yīng)用
在上文中我介紹了Spring Boot使用EhCache 2.x來(lái)作為緩存的實(shí)現(xiàn),本文接著介紹使用單機(jī)版的Redis作為緩存的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08