Java之BigDecimal的使用及說明
一、BigDecimal概述
BigDecimal 是 Java 中用于高精度計算的類,屬于 java.math 包。
它主要用于處理需要極高精度的數(shù)值運算。
記住:
在金融計算、價格計算等需要精確小數(shù)運算的場景中,BigDecimal 是唯一正確的選擇。
二、double、float 類型的坑
double result = 0.1 + 0.2; // 結(jié)果為 0.30000000000000004 float a = 1; float b = 0.9f; System.out.println(a - b); // 結(jié)果為 0.100000024
三、BigDecimal優(yōu)越性
- 高精度數(shù)值計算:BigDecimal是 Java 中用于高精度數(shù)值計算的類。它主要用于處理需要精確表示的十進制數(shù),特別是在金融、貨幣計算等對精度要求極高的領(lǐng)域。雙精度浮點型變量double 雖然可以處理16位有效數(shù),但在實際應用中,可能需要對更大或者更小的數(shù)進行運算和處理,BigDecimal 就可以用來對超過16位有效位的數(shù)進行精確的運算。一般情況下,對于那些不需要準確計算精度的數(shù)字,我們可以直接使用Float和Double處理,但是Double.valueOf(String) 和Float.valueOf(String)會丟失精度。所以開發(fā)中,如果我們需要精確計算的結(jié)果,則必須使用BigDecimal類來操作。
- 不可變對象:BigDecimal對象是不可變的,這意味著一旦創(chuàng)建,其數(shù)值就不能被修改(即線程安全)。對BigDecimal對象進行的任何操作(如加法、減法、乘法、除法等)都會返回一個新的BigDecimal對象,而原對象保持不變。這種不可變性有助于確保數(shù)據(jù)的一致性和線程安全性。
當程序中涉及到金額時,必須使用 BigDecimal 而不是 double 或 float 。
double result = 0.1 + 0.2; // 結(jié)果為 0.30000000000000004
BigDecimal bd1 = new BigDecimal("0.1");
BigDecimal bd2 = new BigDecimal("0.2");
BigDecimal sum = bd1.add(bd2); // 結(jié)果為 0.3
四、BigDecimal 的常用方法
4.1 構(gòu)造方法
- new BigDecimal(int val):創(chuàng)建一個具有參數(shù)所指定整數(shù)值的對象。
- new BigDecimal(double val):(不推薦使用,因為存在精度丟失問題)創(chuàng)建一個具有參數(shù)所指定雙精度值的對象。
- new BigDecimal(long val):創(chuàng)建一個具有參數(shù)所指定長整數(shù)值的對象
- new BigDecimal(String val):(推薦使用)創(chuàng)建一個具有參數(shù)所指定以字符串表示的數(shù)值的對象。
BigDecimal b_int = new BigDecimal(10);
BigDecimal b_double = new BigDecimal(0.1);
BigDecimal b_float = new BigDecimal(0.1f);
BigDecimal b_string = new BigDecimal("0.1");
BigDecimal b_valueof = BigDecimal.valueOf(0.1);
System.out.println("b_int:" + b_int); // b_int:10
System.out.println("b_double:" + b_double); // b_double:0.1000000000000000055511151231257827021181583404541015625
System.out.println("b_float:" + b_float); // b_float:0.100000001490116119384765625
System.out.println("b_string:" + b_string); // b_string:0.1
System.out.println("b_valueof:" + b_valueof); // b_valueof:0.1
使用構(gòu)造函數(shù)時,推薦用 int 或 String 做參數(shù),如果不滿足,則建議使用 BigDecimal.valueOf 方法,該方法可接受 int、long、double、float 做參數(shù),但注意不接受 String。
4.2 算術(shù)運算方法
- BigDecimal add(BigDecimal augend) 加法運算。
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");
BigDecimal sum = a.add(b); // 13.70
- BigDecimal subtract(BigDecimal subtrahend) 減法運算
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");
BigDecimal difference = a.subtract(b); // 7.30
- BigDecimal multiply(BigDecimal multiplicand) 乘法運算
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");
BigDecimal product = a.multiply(b); // 33.600
- BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) 除法運算
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");
// 四舍五入保留2位小數(shù)
BigDecimal quotient1 = a.divide(b, 2, RoundingMode.HALF_UP); // 3.28
// 使用默認舍入模式
BigDecimal quotient2 = a.divide(b, RoundingMode.HALF_UP);
- BigDecimal remainder(BigDecimal divisor) 取余運算
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("3.2");
BigDecimal remainder = a.remainder(b); // 0.9
- BigDecimal[] divideAndRemainder(BigDecimal divisor) 除法取余
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("3.2");
BigDecimal[] results = a.divideAndRemainder(b);
// results[0] = 3 (商)
// results[1] = 0.9 (余數(shù))
- BigDecimal abs() 絕對值
BigDecimal a = new BigDecimal("-10.50");
BigDecimal absolute = a.abs(); // 10.50
- BigDecimal pow(int n) 冪運算
BigDecimal a = new BigDecimal("2.5");
BigDecimal power = a.pow(3); // 15.625
- BigDecimal setScale(int newScale, RoundingMode roundingMode) 四舍五入
BigDecimal a = new BigDecimal("3.1415926");
// 四舍五入保留3位小數(shù)
BigDecimal rounded = a.setScale(3, RoundingMode.HALF_UP); // 3.142
// 直接截斷
BigDecimal truncated = a.setScale(3, RoundingMode.DOWN); // 3.141
- int compareTo(BigDecimal val) 比較運算
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("10.5");
int result = a.compareTo(b);
// result = 0 (相等)
// result < 0 (a < b)
// result > 0 (a > b)
五、BigDecimal遇到的問題
5.1 相除精度丟失的問題
問題:兩數(shù)相除,如果9/3=3整除沒問題,但是10/3=0.33333333…除不盡,這里不能讓電腦一直除不盡,所以BigDecimal做出一些限制;
必須按照(數(shù),保留小數(shù)位(最好要合理限制最大精度),舍入方式)來操作,否則就會拋出異常,例如:
public static void main(String[] args) {
BigDecimal a = new BigDecimal(10);
BigDecimal b = new BigDecimal(3);
BigDecimal c = a.divide(b);
}
執(zhí)行:拋出
Exception in thread “main” java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1616)
5.2 BigDecimal初始化時入?yún)⑹褂肧tring類型
如果不是數(shù)字會拋異常NumberFormatException
// java.lang.NumberFormatException
BigDecimal val = new BigDecimal("a");
System.out.println(val);
5.3 用 equals 判斷相等
BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1.00");
System.out.println(x.equals(y)); //false 盡管 1.0 和 1.00 的數(shù)值相等,但精度不一樣,equals 判定為不同。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java封裝Redis非阻塞分布式鎖徹底解決表單重復提交主鍵沖突問題
本文基于原生RedisTemplate封裝通用非阻塞分布式鎖工具類,實現(xiàn)鎖邏輯與業(yè)務邏輯解耦,兼顧易用性與安全性,同時解決鎖與事務配合、鎖釋放時機、失敗重試等核心坑點,感興趣的朋友跟隨小編一起看看吧2026-03-03
Spring Boot 中使用 Mybatis Plus的操作方法
本文介紹了如何在 Spring Boot 項目中集成 Mybatis Plus,Spring Boot 與 MyBatis Plus 的集成非常簡單,通過自動配置和簡潔的 API,可以大大減少開發(fā)中常見的數(shù)據(jù)庫操作代碼,需要的朋友參考下吧2024-12-12
mybatis中BigDecimal中的0存為null的坑及解決
在使用MyBatis進行數(shù)據(jù)庫操作時,若Java中屬性類型為BigDecimal且值為0,插入數(shù)據(jù)庫時可能會變?yōu)閚ull,而不是0,這個問題可能是由于MyBatis在處理BigDecimal類型時的弱類型判斷導致的,當BigDecimal變量與空字符串進行比較時,MyBatis可能將其視為null2024-10-10

