Java之BigDecimal的使用及說明
一、BigDecimal概述
BigDecimal 是 Java 中用于高精度計(jì)算的類,屬于 java.math 包。
它主要用于處理需要極高精度的數(shù)值運(yùn)算。
記?。?/strong>
在金融計(jì)算、價(jià)格計(jì)算等需要精確小數(shù)運(yùn)算的場(chǎng)景中,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ù)值計(jì)算:BigDecimal是 Java 中用于高精度數(shù)值計(jì)算的類。它主要用于處理需要精確表示的十進(jìn)制數(shù),特別是在金融、貨幣計(jì)算等對(duì)精度要求極高的領(lǐng)域。雙精度浮點(diǎn)型變量double 雖然可以處理16位有效數(shù),但在實(shí)際應(yīng)用中,可能需要對(duì)更大或者更小的數(shù)進(jìn)行運(yùn)算和處理,BigDecimal 就可以用來對(duì)超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算。一般情況下,對(duì)于那些不需要準(zhǔn)確計(jì)算精度的數(shù)字,我們可以直接使用Float和Double處理,但是Double.valueOf(String) 和Float.valueOf(String)會(huì)丟失精度。所以開發(fā)中,如果我們需要精確計(jì)算的結(jié)果,則必須使用BigDecimal類來操作。
- 不可變對(duì)象:BigDecimal對(duì)象是不可變的,這意味著一旦創(chuàng)建,其數(shù)值就不能被修改(即線程安全)。對(duì)BigDecimal對(duì)象進(jìn)行的任何操作(如加法、減法、乘法、除法等)都會(huì)返回一個(gè)新的BigDecimal對(duì)象,而原對(duì)象保持不變。這種不可變性有助于確保數(shù)據(jù)的一致性和線程安全性。
當(dāng)程序中涉及到金額時(shí),必須使用 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)建一個(gè)具有參數(shù)所指定整數(shù)值的對(duì)象。
- new BigDecimal(double val):(不推薦使用,因?yàn)榇嬖诰葋G失問題)創(chuàng)建一個(gè)具有參數(shù)所指定雙精度值的對(duì)象。
- new BigDecimal(long val):創(chuàng)建一個(gè)具有參數(shù)所指定長整數(shù)值的對(duì)象
- new BigDecimal(String val):(推薦使用)創(chuàng)建一個(gè)具有參數(shù)所指定以字符串表示的數(shù)值的對(duì)象。
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ù)時(shí),推薦用 int 或 String 做參數(shù),如果不滿足,則建議使用 BigDecimal.valueOf 方法,該方法可接受 int、long、double、float 做參數(shù),但注意不接受 String。
4.2 算術(shù)運(yùn)算方法
- BigDecimal add(BigDecimal augend) 加法運(yùn)算。
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");
BigDecimal sum = a.add(b); // 13.70
- BigDecimal subtract(BigDecimal subtrahend) 減法運(yùn)算
BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("3.20");
BigDecimal difference = a.subtract(b); // 7.30
- BigDecimal multiply(BigDecimal multiplicand) 乘法運(yùn)算
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) 除法運(yùn)算
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
// 使用默認(rèn)舍入模式
BigDecimal quotient2 = a.divide(b, RoundingMode.HALF_UP);
- BigDecimal remainder(BigDecimal divisor) 取余運(yùn)算
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() 絕對(duì)值
BigDecimal a = new BigDecimal("-10.50");
BigDecimal absolute = a.abs(); // 10.50
- BigDecimal pow(int n) 冪運(yù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
// 直接截?cái)?
BigDecimal truncated = a.setScale(3, RoundingMode.DOWN); // 3.141
- int compareTo(BigDecimal val) 比較運(yùn)算
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ù)位(最好要合理限制最大精度),舍入方式)來操作,否則就會(huì)拋出異常,例如:
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初始化時(shí)入?yún)⑹褂肧tring類型
如果不是數(shù)字會(huì)拋異常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é)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java正則表達(dá)式校驗(yàn)日期格式實(shí)例代碼
如果使用得當(dāng),正則表達(dá)式是匹配各種模式的強(qiáng)大工具,下面這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式校驗(yàn)日期格式的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
Java封裝Redis非阻塞分布式鎖徹底解決表單重復(fù)提交主鍵沖突問題
本文基于原生RedisTemplate封裝通用非阻塞分布式鎖工具類,實(shí)現(xiàn)鎖邏輯與業(yè)務(wù)邏輯解耦,兼顧易用性與安全性,同時(shí)解決鎖與事務(wù)配合、鎖釋放時(shí)機(jī)、失敗重試等核心坑點(diǎn),感興趣的朋友跟隨小編一起看看吧2026-03-03
Spring Boot 中使用 Mybatis Plus的操作方法
本文介紹了如何在 Spring Boot 項(xiàng)目中集成 Mybatis Plus,Spring Boot 與 MyBatis Plus 的集成非常簡單,通過自動(dòng)配置和簡潔的 API,可以大大減少開發(fā)中常見的數(shù)據(jù)庫操作代碼,需要的朋友參考下吧2024-12-12
mybatis中BigDecimal中的0存為null的坑及解決
在使用MyBatis進(jìn)行數(shù)據(jù)庫操作時(shí),若Java中屬性類型為BigDecimal且值為0,插入數(shù)據(jù)庫時(shí)可能會(huì)變?yōu)閚ull,而不是0,這個(gè)問題可能是由于MyBatis在處理BigDecimal類型時(shí)的弱類型判斷導(dǎo)致的,當(dāng)BigDecimal變量與空字符串進(jìn)行比較時(shí),MyBatis可能將其視為null2024-10-10
Java中的FutureTask實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Java中的FutureTask手寫代碼實(shí)例,FutureTask是Future的實(shí)現(xiàn),用來異步任務(wù)的獲取結(jié)果,可以啟動(dòng)和取消異步任務(wù),查詢異步任務(wù)是否計(jì)算結(jié)束以及獲取最終的異步任務(wù)的結(jié)果,需要的朋友可以參考下2023-12-12

