0
点赞
收藏
分享

微信扫一扫

Java--BigDecimal--使用/教程/实例

左手梦圆 2022-03-22 阅读 63


简介

说明

        本文用实例介绍Java中的BigDecimal。包括:用法、使用BigDecimal的场景(为什么使用BigDecimal),使用BigDecimal应该注意的问题。

使用BigDecimal的场景

        典型场景是表示金额。

        对于金额而言,BigDecimal是最好的选择。假如在面试中有面试官问到金额用什么类型表示,若回答BigDecimal,此题过关;若回答double、float之类的,结果很可能就是:回去等通知吧????

        在数据库中,对应的类型是bigdecimal,例如:

Java--BigDecimal--使用/教程/实例_后缀

BigDecimal与double

简介

特点

BigDecimal

double

精准度

绝对精准

小数部分极大可能损失精度

数字长度

可以处理大于16位长度的数

最长只能处理16为长度的数

        Java中提供了java.math.BigInteger 类和 java.math.BigDecimal 类,用于处理超过16位有效位的数字。双精度浮点型变量double可以处理16位有效数。

        一般情况下,对于那些不需要准确计算精度的数字,可直接用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以如果需要精确计算的结果,必须使用BigDecimal类。

实例1:加法

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
double d1 = 0.3;
double d2 = 0.2;
System.out.println("double:\t\t 0.3 - 0.2 = " + (d1 - d2));

float f1 = 0.3f;
float f2 = 0.2f;
System.out.println("float:\t\t 0.3 - 0.2 = " + (f1 - f2));

BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println("BigDecimal:\t 0.3 - 0.2 = " + (bd1.subtract(bd2)));
}
}

执行结果

double:    0.3 - 0.2 = 0.09999999999999998
float: 0.3 - 0.2 = 0.10000001
BigDecimal: 0.3 - 0.2 = 0.1

可见:只有BigDecimal保持了精度。 

实例2:除法

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
double d1 = 10;
double d2 = 3;
System.out.println("double:\t\t 10 / 3 = " + (d1 / d2));

float f1 = 10f;
float f2 = 3f;
System.out.println("float:\t\t 10 / 3 = " + (f1 / f2));

BigDecimal bd1 = new BigDecimal("10");
BigDecimal bd2 = new BigDecimal("3");
System.out.println("BigDecimal:\t 10 / 3 = " + (bd1.divide(bd2, 3, BigDecimal.ROUND_HALF_UP)));
}
}

结果

double:    10 / 3 = 3.3333333333333335
float: 10 / 3 = 3.3333333
BigDecimal: 10 / 3 = 3.333
bd1.divide(bd2, 3, BigDecimal.ROUND_HALF_UP))

结果

double:    10 / 3 = 3.3333333333333335
float: 10 / 3 = 3.3333333
BigDecimal: 10 / 3 = 3.333

构造方法

本处重点介绍带小数的构造方法。其他通过int、long等进行构造的方法不赘述了。

BigDecimal BigDecimal(String s);     //推荐使用
static BigDecimal valueOf(double d); //推荐使用
BigDecimal BigDecimal(double d); //不推荐使用,精度不能保证

实例

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
BigDecimal bigDecimal1 = new BigDecimal("1.11");
BigDecimal bigDecimal2 = BigDecimal.valueOf(1.11);
BigDecimal bigDecimal3 = new BigDecimal(1.11);

System.out.println(bigDecimal1);
System.out.println(bigDecimal2);
System.out.println(bigDecimal3);
}
}

结果:

1.11
1.11
1.1100000000000000976996261670137755572795867919921875

加减乘除

方法

描述

add(BigDecimal)

BigDecimal对象中的值相加,然后返回这个对象

subtract(BigDecimal)

BigDecimal对象中的值相减,然后返回这个对象

multiply(BigDecimal)

BigDecimal对象中的值相乘,然后返回这个对象

divide(BigDecimal)

BigDecimal对象中的值相除,然后返回这个对象

实例

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("2.34");
BigDecimal b2 = new BigDecimal("1.11");

System.out.println(b1.add(b2));
System.out.println(b1.subtract(b2));
System.out.println(b1.multiply(b2));
System.out.println(b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP));
}
}

 结果

3.45
1.23
2.5974
2.11

注意

对于BigDecimal来说,如果结果除不尽,且没有设置进位的状态值,那就会抛出异常。

比如:

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("10");
BigDecimal b2 = new BigDecimal("3");

System.out.println(b1.divide(b2));
}
}

执行结果

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.example.a.Demo.main(Demo.java:10)

所以,必须指定保留的位数,以及如何四舍五入。详见下方“四舍五入”

四舍五入


模式



说明



示例



ROUND_UP



舍入远离零的舍入模式。

始终对非零舍弃部分前面的数字加 1



2.36 -> 2.4



ROUND_DOWN



接近零的舍入模式。

从不对舍弃部分前面的数字加1,即截短。



2.36 -> 2.3



ROUND_CEILING



接近正无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;

如果为负,则舍入行为与 ROUND_DOWN 相同。

相当于是 ROUND_UP 和 ROUND_DOWN 的合集



2.36 -> 2.4

-2.36 -> -2.3



ROUND_FLOOR



接近负无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;

如果为负,则舍入行为与 ROUND_UP 相同。

与 ROUND_CEILING 正好相反



2.36 -> 2.3

-2.36 -> -2.4



ROUND_HALF_UP




四舍五入



2.35 -> 2.4



ROUND_HALF_DOWN



五舍六入。



2.35 -> 2.3



ROUND_HALF_EVEN



如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同(四舍五入);

如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同(五舍六入)。



1.15 -> 1.1,1.25 -> 1.2



ROUND_UNNECESSARY



断言请求的操作具有精确的结果,因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式,则抛出 ArithmeticException。





实例

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
BigDecimal b = new BigDecimal("2.35");
// setScale(1) 表示保留一位小数
System.out.println("ROUND_UP,结果:" + b.setScale(1, BigDecimal.ROUND_UP));
System.out.println("ROUND_DOWN,结果:" + b.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println("ROUND_CEILING,结果:" + b.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println("ROUND_FLOOR,结果:" + b.setScale(1, BigDecimal.ROUND_FLOOR));
System.out.println("ROUND_HALF_UP,结果:" + b.setScale(1, BigDecimal.ROUND_HALF_UP));
System.out.println("ROUND_HALF_DOWN,结果:" + b.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println("ROUND_HALF_EVEN,结果:" + b.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println("ROUND_UNNECESSARY,结果:" + b.setScale(1, BigDecimal.ROUND_UNNECESSARY));
}
}

结果

ROUND_UP,结果:2.4
ROUND_DOWN,结果:2.3
ROUND_CEILING,结果:2.4
ROUND_FLOOR,结果:2.3
ROUND_HALF_UP,结果:2.4
ROUND_HALF_DOWN,结果:2.3
ROUND_HALF_EVEN,结果:2.4
Exception in thread "main" java.lang.ArithmeticException: Rounding necessary
at java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4151)
at java.math.BigDecimal.needIncrement(BigDecimal.java:4207)
at java.math.BigDecimal.divideAndRound(BigDecimal.java:4115)
at java.math.BigDecimal.setScale(BigDecimal.java:2455)
at com.example.a.Demo.main(Demo.java:16)

比较大小

简介

a.compareTo(b)

结果:a > b 返回 1;a = b 返回 0;a < b 返回 -1

实例

package com.example.a;

import java.math.BigDecimal;

public class Demo {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("2.34");
BigDecimal b2 = new BigDecimal("1.11");

System.out.println(b1.compareTo(b2));
}
}

结果

1

格式化(保留位数等)

DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字。


符号



位置



说明



0



数字



阿拉伯数字,如果不存在则显示0



#



数字



阿拉伯数字,如果不存在不显示0



.



数字



小数分隔符或货币小数分隔符



,



数字



分组分隔符



E



数字



分隔科学计数法中的尾数和指数。在前缀或后缀中无需加引号。 



-



数字



负号



;



子模式边界



分隔正数和负数子模式



%



前缀或后缀



乘以 100 并显示为百分数



\u2030



前缀或后缀



乘以 1000 并显示为千分数



¤(\u00A4)



前缀或后缀



货币记号,由货币符号替换。

如果两个同时出现,则用国际货币符号替换。如果出现在某个模式中,则使用货币小数分隔符,而不使用小数分隔符。



'



前缀或后缀



用于在前缀或或后缀中为特殊字符加引号,例如 "'#'#"将 123 格式化为 "#123"。要创建单引号本身,请连续使用两个单引号:"# o''clock"。


数字保留位数(0和#)

package com.example.a;

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Demo {
public static void main(String[] args) {
String stringNum = "12.345678";
BigDecimal num = new BigDecimal(stringNum);

//取所有整数部分
System.out.println("0 :" + new DecimalFormat("0").format(num));
System.out.println("# :" + new DecimalFormat("#").format(num));

//取一位整数和三位小数
System.out.println("0.000 :" + new DecimalFormat("0.000").format(num));
System.out.println("#.### :" + new DecimalFormat("#.###").format(num));

//取3位整数和三位小数,整数不足部分以0填补。
System.out.println("000.000 :" + new DecimalFormat("000.000").format(num));
//取3位整数和三位小数,整数不足不填补。
System.out.println("###.### :" + new DecimalFormat("###.###").format(num));

//以百分比方式计数,并取两位小数
System.out.println("#.##% :" + new DecimalFormat("#.##%").format(num));
//以千分比方式计数,并取两位小数
System.out.println("#.##\u2030 :" + new DecimalFormat("#.##\u2030").format(num));
}
}

结果

0       :12
# :12
0.000 :12.346
#.### :12.346
000.000 :012.346
###.### :12.346
#.##% :1234.57%
#.##‰ :12345.68‰

科学计数法E

package com.example.a;

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Demo {
public static void main(String[] args) {
String stringNum = "1234.567";
BigDecimal num = new BigDecimal(stringNum);

System.out.println(new DecimalFormat("0E0").format(num));
System.out.println(new DecimalFormat("0E00").format(num));
System.out.println(new DecimalFormat("#E0").format(num));
System.out.println(new DecimalFormat("##E0").format(num));
System.out.println(new DecimalFormat("###E0").format(num));
System.out.println(new DecimalFormat("####E0").format(num));
System.out.println(new DecimalFormat("#####E0").format(num));
System.out.println(new DecimalFormat("######E0").format(num));
System.out.println(new DecimalFormat("#######E0").format(num));
System.out.println(new DecimalFormat("########E0").format(num));
}
}

执行结果

1E3
1E03
.1E4
12E2
1.23E3
1235E0
1234.6E0
1234.57E0
1234.567E0
1234.567E0

分隔符和减号

分隔符

package com.example.a;

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Demo {
public static void main(String[] args) {
String stringNum = "1234567.89";
BigDecimal num = new BigDecimal(stringNum);

System.out.println(new DecimalFormat(",###").format(num));
System.out.println(new DecimalFormat(",##").format(num));
}
}

结果

1,234,568
1,23,45,68

减号(负数) 

​-​​表示输出为负数, 要放在最前面

package com.example.a;

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Demo {
public static void main(String[] args) {
String stringNum = "1234.56789";
BigDecimal num = new BigDecimal(stringNum);

System.out.println(new DecimalFormat("-#.#").format(num));
}
}

结果

-1234.56789

货币

package com.example.a;

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Demo {
public static void main(String[] args) {
String stringNum = "1234.56789";
BigDecimal num = new BigDecimal(stringNum);

System.out.println(new DecimalFormat(",000.00¤").format(num));
System.out.println(new DecimalFormat(",000.¤00").format(num));
System.out.println(new DecimalFormat("¤,000.00").format(num));
System.out.println(new DecimalFormat(",00¤0.¤00").format(num));
System.out.println(new DecimalFormat("¤,000.¤00").format(num));
System.out.println(new DecimalFormat(",000.00¤¤").format(num));
}
}

结果

1,234.57¥
1,234.57¥
¥1,234.57
1,234.57¥¥
¥1,234.57¥
1,234.57CNY

引号

' 用于引用特殊的字符,作为前缀或后缀。

package com.example.a;

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Demo {
public static void main(String[] args) {
String stringNum = "1234.56789";
BigDecimal num = new BigDecimal(stringNum);

//使用#本身作为前缀或后缀
System.out.println(new DecimalFormat("'#'0.00").format(num));//#4.57
//使用'本身作为前缀或后缀
System.out.println(new DecimalFormat("''0.00").format(num));//'4.57
}
}

结果

#1234.57
'1234.57

其他网址

BigDecimal 使用总结--

BigDecimal使用(整理) - 简书


举报

相关推荐

0 条评论