最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Java中的金錢陷阱

2023-06-07 15:09 作者:程序員-王堅(jiān)  | 我要投稿

前言

有多少小伙伴是被標(biāo)題?騙?吸引進(jìn)來(lái)的呢,我可不是標(biāo)題黨,今天的文章呢確實(shí)跟”金錢“有關(guān)系。

但是我們說(shuō)的不是過(guò)度追求金錢而掉入陷阱,而是要說(shuō)一說(shuō)在Java程序中,各種跟金錢運(yùn)算有關(guān)的陷阱。

日常工作中我們經(jīng)常會(huì)涉及到各種金額這樣浮點(diǎn)數(shù)的運(yùn)算。

一旦涉及到金額的運(yùn)算就必須慎之又慎,一旦有精度丟失,或者其他運(yùn)算錯(cuò)誤就可能造成無(wú)可挽回的損失。

一 、 存在的陷阱

這一小節(jié)我們先將陷阱列出來(lái),下一小節(jié)分別給出解決方案。

我們先來(lái)看看到底有哪些坑等著我們?nèi)ゲ?/p>

1.1 浮點(diǎn)運(yùn)算精度丟失陷阱

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?float a = 1.0f - 0.9f; ? ? ? ?float b = 0.9f - 0.8f; ? ? ? ?System.out.println("a= "+a); ? ? ? ?System.out.println("b= "+b); ? ?} }//輸出結(jié)果a= 0.100000024b= 0.099999964

1.2 浮點(diǎn)數(shù)等值判斷陷阱

① 基本類型與包裝類型判斷浮點(diǎn)數(shù)是否相等

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?float a = 1.0F - 0.9F; ? ? ? ?float b = 0.9F - 0.8F; ? ? ? ?System.out.println("通過(guò)==判斷a與b是否相等:"+ (a == b)); ? ? ? ?Float x = Float.valueOf(a); ? ? ? ?Float y = Float.valueOf(b); ? ? ? ?System.out.println("通過(guò)equals方法判斷x與y是否相等:"+ x.equals(y)); ? ?} }//輸出結(jié)果通過(guò)==判斷a與b是否相等false通過(guò)equals方法判斷x y是否相等false

BigDecimal類通過(guò)equals?方法判斷是否相等

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal("2"); ? ? ? ?BigDecimal b = new BigDecimal("2.0"); ? ? ? ?System.out.println(a.equals(b)); ? ?} }//輸出結(jié)果false

1.3?BigDecimal?構(gòu)造方法中的陷阱

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal(0.1f); ? ? ? ? ? ? ? ?System.out.println("a= "+ a); ? ?} }//輸出結(jié)果a= 0.100000001490116119384765625

1.4?BigDecimal?除法陷阱

如果兩數(shù)相除無(wú)法除盡,拋出?ArithmeticException?異常

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal("0.2"); ? ? ? ?BigDecimal b = new BigDecimal("0.3"); ? ? ? ?System.out.println(a.divide(b)); ? ?} }//輸出結(jié)果Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.math.BigDecimal.divide(BigDecimal.java:1693) at com.xiezhr.BigDecimalDemo.main(BigDecimalDemo.java:17)

二、避免陷阱

2.1 浮點(diǎn)數(shù)運(yùn)算避坑

① 我們先來(lái)看看為什么浮點(diǎn)數(shù)(也就是float?和double?關(guān)鍵字定義的數(shù)) 運(yùn)算的時(shí)候精度會(huì)丟失?

我們直到計(jì)算機(jī)是以二進(jìn)制的方式進(jìn)行數(shù)據(jù)存儲(chǔ)的,在表示一個(gè)數(shù)字時(shí),寬度時(shí)有限的。

十進(jìn)制的 0.1 轉(zhuǎn)為二進(jìn)制,得到一個(gè)無(wú)限循環(huán)小數(shù):0.00011… (看不懂的自覺點(diǎn)回去翻一翻大一的《計(jì)算機(jī)基礎(chǔ)》課本)

無(wú)限循環(huán)的小數(shù)存儲(chǔ)在計(jì)算機(jī)時(shí),只能被截?cái)?,所以就?huì)導(dǎo)致小數(shù)精度發(fā)生損失的情況。

這就是為什么浮點(diǎn)數(shù)沒有辦法用二進(jìn)制精確表示。

我們?cè)趺磥?lái)填1.1 中的坑呢?

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal("1.0"); ? ? ? ?BigDecimal b = new BigDecimal("0.9"); ? ? ? ?BigDecimal c = new BigDecimal("0.9"); ? ? ? ?BigDecimal d = new BigDecimal("0.8"); ? ? ? ?System.out.println("a-b = "+a.subtract(b)); ? ? ? ?System.out.println("c-d = "+c.subtract(d)); ? ?} }//輸出結(jié)果a-b = 0.1c-d = 0.1

2.2 浮點(diǎn)數(shù)等值判斷避坑

日常開發(fā)中肯定時(shí)免不了比較兩個(gè)浮點(diǎn)數(shù)大小的,這里呢就把1.2中的坑給填上

① 指定一個(gè)誤差范圍,若兩個(gè)浮點(diǎn)數(shù)的差值在誤差范圍內(nèi),則認(rèn)為兩個(gè)浮點(diǎn)數(shù)時(shí)相等的

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?float a = 1.0F - 0.9F; ? ? ? ?float b = 0.9F - 0.8F; ? ? ? ?//表示10的-6次方 ? ? ? ?float diff = 1e-6f; ? ? ? ?if (Math.abs(a - b )< diff) { ? ? ? ? ? ?System.out.println("a與b相等"); ? ? ? ?} ? ?} }//輸出結(jié)果a與b相等

② 使用BigDecimal定義值,再進(jìn)行運(yùn)算操作,最后使用compareTo?方法比較

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal("1.0"); ? ? ? ?BigDecimal b = new BigDecimal("0.9"); ? ? ? ?BigDecimal c = new BigDecimal("0.8"); ? ? ? ?BigDecimal x = a.subtract(b); ? ? ? ?BigDecimal y = b.subtract(c); ? ? ? ?if(x.compareTo(y)==0){ ? ? ? ? ? ?System.out.println("x與y相等"); ? ? ? ?} ? ?} }//輸出結(jié)果x與y相等

2.3?BigDecimal?構(gòu)造方法避坑

陷阱的產(chǎn)生:

  • double的構(gòu)造方法的結(jié)果有一定的不可預(yù)知性,

    newBigDecimal(1.0)所創(chuàng)建的實(shí)際上等于0.1000000000000000055511151231257827021181583404541015625。

    因?yàn)?.1無(wú)法準(zhǔn)確地表示為 double,傳入到構(gòu)造方法的值不會(huì)正好等于 0.1

  • String?構(gòu)造方法是完全可預(yù)知的

寫入?newBigDecimal("0.1")?將創(chuàng)建一個(gè)?BigDecimal,它正好等于預(yù)期的 0.1

這里來(lái)填1.3中的坑,這里有兩種方案

《阿里巴巴Java開發(fā)手冊(cè)》1.4 OOP 規(guī)約中提到

??【強(qiáng)制】?禁止使用構(gòu)造方法BigDecimal(double)的方式把double值 轉(zhuǎn)換為BigDecimal?對(duì)象

說(shuō)明:?BigDecimal(double)?存在精度損失風(fēng)險(xiǎn),在精確計(jì)算或值比較的場(chǎng)景中,可能會(huì)導(dǎo)致業(yè)務(wù)邏輯出現(xiàn)異常。

如:BigDecimal g = new BigDecimal(0.1f); 實(shí)際存儲(chǔ)值為:0.100000001490116119384765625

正例:?優(yōu)先推薦入?yún)?code>String?的構(gòu)造方法,或使用BigDecimal?的?valueOf?方法。

此方法內(nèi)部其實(shí)執(zhí)行了Double?的toString, 而Double?的?toString?按double?的實(shí)際能表達(dá)的精度對(duì)尾數(shù)進(jìn)行了截?cái)唷?/p>

BigDecimal good1 = new BigDecimal("0.1");BigDecimal good2 = BigDecimal.valueOf(0.1);

①將BigDecimal(double)?==》BigDecimal(String)

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal(Double.toString(0.1)); ? ? ? ?System.out.println("a=" + a); ? ?} }//輸出結(jié)果a=0.1

②使用BigDecimal類的valueOf?方法

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = ?BigDecimal.valueOf(0.1); ? ? ? ?System.out.println("a=" + a); ? ?} }//輸出結(jié)果a=0.1

2.4?BigDecimal?除法避坑

我們使用帶有3個(gè)參數(shù)的divide?方法來(lái)填1.4中的坑

BigDecimal.divide(BigDecimal divisor, int scale, RoundingMode roundingMode)?方法的具體使用我們?cè)傧乱恍」?jié)中再詳細(xì)說(shuō)

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ?BigDecimal a = new BigDecimal("0.2"); ? ? ? ?BigDecimal b = new BigDecimal("0.3"); //這里就簡(jiǎn)單的看作四舍五入就行了 ? ? ? ?System.out.println("a除以b等于:"+ a.divide(b, 2, RoundingMode.HALF_UP)); ? ?} }//輸出結(jié)果a除以b等于:0.67

三、BigDecimal?常用方法

  • 常用構(gòu)造方法

  • 常用方法

3.1 加法運(yùn)算 add

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? BigDecimal a = new BigDecimal(Double.toString(0.1)); ? ? ? BigDecimal b = BigDecimal.valueOf(0.2); ? ? ? ?System.out.println("a + b ="+a.add(b)); ? ?} }//輸出結(jié)果a + b =0.3

3.2 減法運(yùn)算 subtract

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? BigDecimal a = new BigDecimal(Double.toString(3.5)); ? ? ? BigDecimal b = BigDecimal.valueOf(2.1); ? ? ? ?System.out.println("a - b ="+a.subtract(b)); ? ?} }//輸出結(jié)果a - b =1.4

3.3 乘法運(yùn)算 multiply

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? BigDecimal a = new BigDecimal(Double.toString(2.5)); ? ? ? BigDecimal b = BigDecimal.valueOf(3.26); ? ? ? ?System.out.println("a * b ="+a.multiply(b)); ? ?} }//輸出結(jié)果a * b =8.150

3.4 除法運(yùn)算 divide

BigDecimal除法可能出現(xiàn)不能整除的情況,比如 1.2/1.3,

這時(shí)會(huì)報(bào)錯(cuò)java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

這個(gè)之前也說(shuō)過(guò),這里呢再詳細(xì)說(shuō)說(shuō)divide?方法

BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

  • divisor?: 表示除數(shù)

  • scale: 表示小數(shù)點(diǎn)后保留位數(shù)

  • roundingMode: 表示舍入模式。roundingMode是一個(gè)枚舉類,有八種舍入模式

    我們以0.333 和-0.333保留2位小數(shù)為例,采用不同模式后得結(jié)果為

    --模式--模式說(shuō)明圖形說(shuō)明UP遠(yuǎn)離0的舍入模式【0.333-->0.34 -0.333 -->-0.34

  • DOWN接近0的舍入模式【0.333-->0.33 -0.333 -->-0.33

  • CEILINGCEILING英文是天花板的意思,可以理解為向”大“舍入【0.333-->0.34 -0.333 -->-0.33

  • FLOORFLOOR有地板的意思,可以理解為向”小“舍入【0.333-->0.33 -0.333 -->-0.34

  • HALF_UP向“最接近的”數(shù)字舍入,如果與兩個(gè)相鄰數(shù)字的距離相等,則為向上舍入的舍入其實(shí)就是四舍五入>=0.5 入,<0.5的舍去HALF_DOWN向“最接近的”數(shù)字舍入,如果與兩個(gè)相鄰數(shù)字的距離相等,則為上舍入的舍入,其實(shí)就是五舍六入?【>0.5 的入,<=0.5 的舍去HALF_EVEN向“最接近的”數(shù)字舍入,如果與兩個(gè)相鄰數(shù)字的距離相等,則向相鄰的偶數(shù)舍入【0.135-->0.14 0.125-->0.12UNNECESSARY斷言請(qǐng)求的操作具有精確的結(jié)果,因此不需要舍入

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ? ? ?BigDecimal numA = new BigDecimal("1"); ? ? ? ? ? ?BigDecimal numB = new BigDecimal("-1"); ? ? ? ? ? ?BigDecimal numC = new BigDecimal("3"); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為UP ? ? ? ? ? ?System.out.println("1/3保留兩位小數(shù)(UP) = " + numA.divide(numC, 2, RoundingMode.UP)); ? ? ? ? ? ?System.out.println("-1/3保留兩位小數(shù)(UP) = " + numB.divide(numC, 2, RoundingMode.UP)); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為DOWN ? ? ? ? ? ?System.out.println("1/3保留兩位小數(shù)(DOWN) = " + numA.divide(numC, 2, RoundingMode.DOWN)); ? ? ? ? ? ?System.out.println("-1/3保留兩位小數(shù)(DOWN) = " + numB.divide(numC, 2, RoundingMode.DOWN)); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為CEILING ? ? ? ? ? ?System.out.println("1/3保留兩位小數(shù)(CEILING) = " + numA.divide(numC, 2, RoundingMode.CEILING)); ? ? ? ? ? ?System.out.println("-1/3保留兩位小數(shù)(CEILING) = " + numB.divide(numC, 2, RoundingMode.CEILING)); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為FLOOR ? ? ? ? ? ?System.out.println("1/3保留兩位小數(shù)(FLOOR) = " + numA.divide(numC, 2, RoundingMode.FLOOR)); ? ? ? ? ? ?System.out.println("-1/3保留兩位小數(shù)(FLOOR) = " + numB.divide(numC, 2, RoundingMode.FLOOR)); ? ? ? ? ? ?BigDecimal numD = new BigDecimal("1"); ? ? ? ? ? ?BigDecimal numE = new BigDecimal("-1"); ? ? ? ? ? ?BigDecimal numF = new BigDecimal("8"); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為HALF_UP ? ? ? ? ? ?System.out.println("1/8(=0.125)保留兩位小數(shù)(HALF_UP) = " + numD.divide(numF, 2, RoundingMode.HALF_UP)); ? ? ? ? ? ?System.out.println("-1/8(=0.125)保留兩位小數(shù)(HALF_UP) = " + numE.divide(numF, 2, RoundingMode.HALF_UP)); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為HALF_DOWN ? ? ? ? ? ?System.out.println("1/8(=0.125)保留兩位小數(shù)(HALF_DOWN) = " + numD.divide(numF, 2, RoundingMode.HALF_DOWN)); ? ? ? ? ? ?System.out.println("-1/8(=0.125)保留兩位小數(shù)(HALF_DOWN) = " + numE.divide(numF, 2, RoundingMode.HALF_DOWN)); ? ? ? ? ? ?// 保留兩位小數(shù),舍入模式為HALF_EVEN ? ? ? ? ? ?System.out.println("0.54/4(=0.135)保留兩位小數(shù)(HALF_EVEN) = " + new BigDecimal("0.54").divide(new BigDecimal("4"), 2, RoundingMode.HALF_EVEN)); ? ? ? ? ? ?System.out.println("1/8(=0.125)保留兩位小數(shù)(HALF_EVEN) = " + numE.divide(numF, 2, RoundingMode.HALF_EVEN)); ? ? ? ? ? ?//UNNECESSARY,會(huì)報(bào)異常 ? ? ? ? ? ?System.out.println("1/8(=0.125) = " + numE.divide(numF, ?RoundingMode.UNNECESSARY)); ? ? ? ?} }//輸出結(jié)果1/3保留兩位小數(shù)(UP) = 0.34-1/3保留兩位小數(shù)(UP) = -0.341/3保留兩位小數(shù)(DOWN) = 0.33-1/3保留兩位小數(shù)(DOWN) = -0.331/3保留兩位小數(shù)(CEILING) = 0.34-1/3保留兩位小數(shù)(CEILING) = -0.331/3保留兩位小數(shù)(FLOOR) = 0.33-1/3保留兩位小數(shù)(FLOOR) = -0.341/8(=0.125)保留兩位小數(shù)(HALF_UP) = 0.13-1/8(=0.125)保留兩位小數(shù)(HALF_UP) = -0.131/8(=0.125)保留兩位小數(shù)(HALF_DOWN) = 0.12-1/8(=0.125)保留兩位小數(shù)(HALF_DOWN) = -0.120.54/4(=0.135)保留兩位小數(shù)(HALF_EVEN) = 0.141/8(=0.125)保留兩位小數(shù)(HALF_EVEN) = -0.12Exception in thread "main" java.lang.ArithmeticException: Rounding necessary

3.5 值轉(zhuǎn)換

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ? ? ?BigDecimal a = new BigDecimal(Double.toString(2.3)); ? ? ? ? ? ?BigDecimal b = new BigDecimal(10200000); ? ? ? ? ? ?System.out.println("BigDecimal轉(zhuǎn)字符串:"+a.toString()); ? ? ? ? ? ?System.out.println("BigDecimal轉(zhuǎn)double:"+a.doubleValue()); ? ? ? ? ? ?System.out.println("BigDecimal轉(zhuǎn)float:"+a.floatValue()); ? ? ? ? ? ?System.out.println("BigDecimal轉(zhuǎn)長(zhǎng)整型:"+b.longValue()); ? ? ? ? ? ?System.out.println("BigDecimal轉(zhuǎn)int:"+b.intValue()); ? ?} }//輸出結(jié)果BigDecimal轉(zhuǎn)字符串:2.3BigDecimal轉(zhuǎn)double2.3BigDecimal轉(zhuǎn)float2.3BigDecimal轉(zhuǎn)長(zhǎng)整型:10200000BigDecimal轉(zhuǎn)int10200000

3.6 絕對(duì)值 abs

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ? ? ?BigDecimal a = new BigDecimal(Double.toString(2.35)); ? ? ? ? ? ?BigDecimal b = BigDecimal.valueOf(-2.35); ? ? ? ? ? ?System.out.println("a的絕對(duì)值是:" + a.abs()); ? ? ? ? ? ?System.out.println("b的絕對(duì)值是:" + b.abs()); ? ?} }//輸出結(jié)果a的絕對(duì)值是:2.35b的絕對(duì)值是:2.35

3.7 等值比較

《阿里巴巴Java開發(fā)手冊(cè)》第一章 1.4 OOP規(guī)約 中提到

?【強(qiáng)制】?浮點(diǎn)數(shù)之間的等值判斷,基本數(shù)據(jù)類型不能用==進(jìn)行比較,包裝數(shù)據(jù)類型不能用equals方法判斷。

說(shuō)明: 浮點(diǎn)數(shù)采用“尾數(shù)+階碼”的編碼方式,類似于科學(xué)計(jì)數(shù)法的“有效數(shù)字+指數(shù)“ 的表示方式。

二級(jí)制無(wú)法精確表示大部分十進(jìn)制小數(shù),具體原理參考《碼出高效,Java開發(fā)手冊(cè)》

反例: ? ?float a = 1.0f - 0.9f; ? ?float b = 0.9f - 0.8 f; if(a==b){ ? ? ? ?//預(yù)期進(jìn)入此代碼塊,執(zhí)行其他業(yè)務(wù)邏輯 ? ? ? ?//但事實(shí)上a==b 的結(jié)果為false ? ?} Float x = Float.valueOf(a); Float y = Float.valueOf(b); if(x.equals(y)){ ? ? ? ?// 預(yù)期進(jìn)入此代碼塊,執(zhí)行其他業(yè)務(wù)邏輯 ? ? ? ?//但事實(shí)上x.equals(y)的結(jié)果為false ? ?} 正例: ? ?1)指定一個(gè)誤差范圍,若兩個(gè)浮點(diǎn)數(shù)的差值在此范圍之內(nèi),則認(rèn)為是相等的。 ? ?float a = 1.0f - 0.9f; ? ?float b = 0.9f - 0.8f; //10的-6次方 float diff = 1e-6f; if(Math.abs(a-b)<diff){ ? ? ? ?System.out.println("true"); ? ?} 2)使用BigDecimal定義值,再進(jìn)行浮點(diǎn)數(shù)的運(yùn)算操作。 ? ?BigDecimal a = BigDecimal("0.1"); ? ?BigDecimal b = BigDecimal("0.9"); ? ?BigDecimal c = BigDecimal("0.8"); BigDecimal x = a.subtract(b); BigDecimal y = b.subtract(c); /** *BigDecimal的等值比較應(yīng)使用compareTo()方法,而不是equals() 方法。 *說(shuō)明:equals()方法會(huì)比較值和精度(1.0 與1.00 返回結(jié)果為false), *而compareTo()則會(huì)忽略精度。 **/ if (x.compareTo(y)==0){ ? ? ? ?System.out.println("true"); ? ?}

等值比較compareTo(BigDecimal val)?方法

a.compareTo(b)

  • -1:表示a小于b

  • 0:表示a等于b

  • 1:表示a大于b

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ? ? ?BigDecimal a = new BigDecimal("0.5"); ? ? ? ? ? ?BigDecimal b = new BigDecimal("0.8"); ? ? ? ? ? ?BigDecimal c = new BigDecimal("0.3"); ? ? ? ? ? ?BigDecimal d = new BigDecimal("0.5"); ? ? ? ? ? ?System.out.println("a與b比較結(jié)果:"+a.compareTo(b)); ? ? ? ? ? ?System.out.println("a與c比較結(jié)果:"+a.compareTo(c)); ? ? ? ? ? ?System.out.println("a與d比較結(jié)果:"+a.compareTo(d)); ? ?} }//輸出結(jié)果a與b比較結(jié)果:-1a與c比較結(jié)果:1a與d比較結(jié)果:0

四、BigDecimal格式化

NumberFormat類的format()方法可以使用BigDecimal對(duì)象作為參數(shù),

可以對(duì)超出16位有效數(shù)字的貨幣值,百分值,以及一般數(shù)值進(jìn)行格式化控制

public class BigDecimalDemo { ? ?public static void main(String[] args) { ? ? ? ? ? ?NumberFormat money = NumberFormat.getCurrencyInstance(); //建立貨幣格式化引用 ? ? ? ? ? ?NumberFormat percent = NumberFormat.getPercentInstance(); ?//建立百分比格式化引用 ? ? ? ? ? ?percent.setMaximumFractionDigits(3); //百分比小數(shù)點(diǎn)最多3位 ? ? ? ? ? ?BigDecimal loanAmount = new BigDecimal("15000.48"); //貸款金額 ? ? ? ? ? ?BigDecimal interestRate = new BigDecimal("0.008"); //利率 ? ? ? ? ? ?BigDecimal interest = loanAmount.multiply(interestRate); //相乘 ? ? ? ? ? ?System.out.println("貸款金額:" + money.format(loanAmount)); ? ? ? ? ? ?System.out.println("利率:" + percent.format(interestRate)); ? ? ? ? ? ?System.out.println("利息:" + money.format(interest)); ? ?} }//輸出結(jié)果貸款金額:¥15,000.48利率:0.8% 利息:¥120.00

五、BigDecimal?工具類

為了更加方便的使用BigDecimal?我們可以將其常用方法封裝成工具類

package com.xiezhr.util;import java.math.BigDecimal;import java.math.RoundingMode;/** * 簡(jiǎn)化BigDecimal計(jì)算的小工具類 */public class BigDecimalUtil { ? ?/** ? ? * 默認(rèn)除法運(yùn)算精度 ? ? */ ? ?private static final int DEF_DIV_SCALE = 10; ? ?private BigDecimalUtil() { ? ?} ? ?/** ? ? * 提供精確的加法運(yùn)算。 ? ? * ? ? * @param v1 被加數(shù) ? ? * @param v2 加數(shù) ? ? * @return 兩個(gè)參數(shù)的和 ? ? */ ? ?public static double add(double v1, double v2) { ? ? ? ?BigDecimal b1 = BigDecimal.valueOf(v1); ? ? ? ?BigDecimal b2 = BigDecimal.valueOf(v2); ? ? ? ?return b1.add(b2).doubleValue(); ? ?} ? ?/** ? ? * 提供精確的減法運(yùn)算。 ? ? * ? ? * @param v1 被減數(shù) ? ? * @param v2 減數(shù) ? ? * @return 兩個(gè)參數(shù)的差 ? ? */ ? ?public static double subtract(double v1, double v2) { ? ? ? ?BigDecimal b1 = BigDecimal.valueOf(v1); ? ? ? ?BigDecimal b2 = BigDecimal.valueOf(v2); ? ? ? ?return b1.subtract(b2).doubleValue(); ? ?} ? ?/** ? ? * 提供精確的乘法運(yùn)算。 ? ? * ? ? * @param v1 被乘數(shù) ? ? * @param v2 乘數(shù) ? ? * @return 兩個(gè)參數(shù)的積 ? ? */ ? ?public static double multiply(double v1, double v2) { ? ? ? ?BigDecimal b1 = BigDecimal.valueOf(v1); ? ? ? ?BigDecimal b2 = BigDecimal.valueOf(v2); ? ? ? ?return b1.multiply(b2).doubleValue(); ? ?} ? ?/** ? ? * 提供(相對(duì))精確的除法運(yùn)算,當(dāng)發(fā)生除不盡的情況時(shí),精確到 ? ? * 小數(shù)點(diǎn)以后10位,以后的數(shù)字四舍五入。 ? ? * ? ? * @param v1 被除數(shù) ? ? * @param v2 除數(shù) ? ? * @return 兩個(gè)參數(shù)的商 ? ? */ ? ?public static double divide(double v1, double v2) { ? ? ? ?return divide(v1, v2, DEF_DIV_SCALE); ? ?} ? ?/** ? ? * 提供(相對(duì))精確的除法運(yùn)算。當(dāng)發(fā)生除不盡的情況時(shí),由scale參數(shù)指 ? ? * 定精度,以后的數(shù)字四舍五入。 ? ? * ? ? * @param v1 ? ?被除數(shù) ? ? * @param v2 ? ?除數(shù) ? ? * @param scale 表示表示需要精確到小數(shù)點(diǎn)以后幾位。 ? ? * @return 兩個(gè)參數(shù)的商 ? ? */ ? ?public static double divide(double v1, double v2, int scale) { ? ? ? ?if (scale < 0) { ? ? ? ? ? ?throw new IllegalArgumentException( ? ? ? ? ? ? ? ? ? ?"The scale must be a positive integer or zero"); ? ? ? ?} ? ? ? ?BigDecimal b1 = BigDecimal.valueOf(v1); ? ? ? ?BigDecimal b2 = BigDecimal.valueOf(v2); ? ? ? ?return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); ? ?} ? ?/** ? ? * 提供精確的小數(shù)位四舍五入處理。 ? ? * ? ? * @param v ? ? 需要四舍五入的數(shù)字 ? ? * @param scale 小數(shù)點(diǎn)后保留幾位 ? ? * @return 四舍五入后的結(jié)果 ? ? */ ? ?public static double round(double v, int scale) { ? ? ? ?if (scale < 0) { ? ? ? ? ? ?throw new IllegalArgumentException( ? ? ? ? ? ? ? ? ? ?"The scale must be a positive integer or zero"); ? ? ? ?} ? ? ? ?BigDecimal b = BigDecimal.valueOf(v); ? ? ? ?BigDecimal one = new BigDecimal("1"); ? ? ? ?return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); ? ?} ? ?/** ? ? * 提供精確的類型轉(zhuǎn)換(Float) ? ? * ? ? * @param v 需要被轉(zhuǎn)換的數(shù)字 ? ? * @return 返回轉(zhuǎn)換結(jié)果 ? ? */ ? ?public static float convertToFloat(double v) { ? ? ? ?BigDecimal b = new BigDecimal(v); ? ? ? ?return b.floatValue(); ? ?} ? ?/** ? ? * 提供精確的類型轉(zhuǎn)換(Int)不進(jìn)行四舍五入 ? ? * ? ? * @param v 需要被轉(zhuǎn)換的數(shù)字 ? ? * @return 返回轉(zhuǎn)換結(jié)果 ? ? */ ? ?public static int convertsToInt(double v) { ? ? ? ?BigDecimal b = new BigDecimal(v); ? ? ? ?return b.intValue(); ? ?} ? ?/** ? ? * 提供精確的類型轉(zhuǎn)換(Long) ? ? * ? ? * @param v 需要被轉(zhuǎn)換的數(shù)字 ? ? * @return 返回轉(zhuǎn)換結(jié)果 ? ? */ ? ?public static long convertsToLong(double v) { ? ? ? ?BigDecimal b = new BigDecimal(v); ? ? ? ?return b.longValue(); ? ?} ? ?/** ? ? * 返回兩個(gè)數(shù)中大的一個(gè)值 ? ? * ? ? * @param v1 需要被對(duì)比的第一個(gè)數(shù) ? ? * @param v2 需要被對(duì)比的第二個(gè)數(shù) ? ? * @return 返回兩個(gè)數(shù)中大的一個(gè)值 ? ? */ ? ?public static double returnMax(double v1, double v2) { ? ? ? ?BigDecimal b1 = new BigDecimal(v1); ? ? ? ?BigDecimal b2 = new BigDecimal(v2); ? ? ? ?return b1.max(b2).doubleValue(); ? ?} ? ?/** ? ? * 返回兩個(gè)數(shù)中小的一個(gè)值 ? ? * ? ? * @param v1 需要被對(duì)比的第一個(gè)數(shù) ? ? * @param v2 需要被對(duì)比的第二個(gè)數(shù) ? ? * @return 返回兩個(gè)數(shù)中小的一個(gè)值 ? ? */ ? ?public static double returnMin(double v1, double v2) { ? ? ? ?BigDecimal b1 = new BigDecimal(v1); ? ? ? ?BigDecimal b2 = new BigDecimal(v2); ? ? ? ?return b1.min(b2).doubleValue(); ? ?} ? ?/** ? ? * 精確對(duì)比兩個(gè)數(shù)字 ? ? * ? ? * @param v1 需要被對(duì)比的第一個(gè)數(shù) ? ? * @param v2 需要被對(duì)比的第二個(gè)數(shù) ? ? * @return 如果兩個(gè)數(shù)一樣則返回0,如果第一個(gè)數(shù)比第二個(gè)數(shù)大則返回1,反之返回-1 ? ? */ ? ?public static int compareTo(double v1, double v2) { ? ? ? ?BigDecimal b1 = BigDecimal.valueOf(v1); ? ? ? ?BigDecimal b2 = BigDecimal.valueOf(v2); ? ? ? ?return b1.compareTo(b2); ? ?} }

六、避坑小結(jié)

  • 商業(yè)計(jì)算使用BigDecimal

  • 盡量使用參數(shù)類型為String的構(gòu)造函數(shù)

  • BigDecimal都是不可變的,在進(jìn)行每一步運(yùn)算時(shí),都會(huì)產(chǎn)生一個(gè)新的對(duì)象,所以在做加減乘除運(yùn)算時(shí)千萬(wàn)要保存操作后的值

通過(guò)本期內(nèi)容,你還會(huì)掉金錢陷阱里么?

本期內(nèi)容到此就結(jié)束了,我們下期再見。(●'?'●)


Java中的金錢陷阱的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
上林县| 新民市| 武鸣县| 阜康市| 湄潭县| 三河市| 时尚| 新乐市| 长春市| 滨州市| 增城市| 贵溪市| 昌宁县| 潮安县| 德安县| 松江区| 且末县| 铜陵市| 广州市| 江口县| 周至县| 保德县| 利川市| 宁强县| 曲阜市| 顺昌县| 扎囊县| 青川县| 南开区| 郎溪县| 荣成市| 馆陶县| 通渭县| 嵊泗县| 仁布县| 隆子县| 永福县| 海兴县| 惠水县| 鲜城| 康平县|