Java BigDecimal的构造方法介绍


本文采用的是jdk11版本的java。
BigDecimal是用来记录计算精确小数的工具,因为double计数会导致数据出错,所以在对小数精度有高度需求的行业中比如买卖商品的价格,用户的余额等等,会使用BigDecimal记录数据。

构造方法

BigDecimal构造方法
上图是我在api中的截图,通过上图我们可以看到一个数据作为参数时,BigDecimal对象将其值存储。

无MathContext的构造方法

下面给出一个参数的构造方法得到BigDecimal对象的代码示例:

    public static void main(String[] args) {
        char[] charTest = {'1','2'};
        double doubleTest = 1.5;
        int intTest = 2;
        long longTest = 200L;
        String stringTest = "1231546";

        BigDecimal bdtest1 = new BigDecimal(charTest);
        BigDecimal bdtest2 = new BigDecimal(doubleTest);
        BigDecimal bdtest3 = new BigDecimal(intTest);
        BigDecimal bdtest4 = new BigDecimal(longTest);
        BigDecimal bdtest5 = new BigDecimal(stringTest);

        System.out.println("charTest(bdtest1) = " + bdtest1);
        System.out.println("doubleTest(bdtest2) = " + bdtest2);
        System.out.println("intTest(bdtest3) = " + bdtest3);
        System.out.println("longTest(bdtest4) = " + bdtest4);
        System.out.println("stringTest(bdtest5) = " + bdtest5);

    }

下面是运行结果图:
BigDecimal运行结果

在这之外,我还发现实际上他对String类型以及char[]类型的数据内容是有一定的要求的,我发现有很多情况他会报错,比如:
1.有两个小数点
2.有不为数字 也不是e的字母
3.数字过大,导致越界
我对上述情况都做了试验,其中的代码如下:

1.两个小数点的情况:

        String srtTest = "123.123.123";
        BigDecimal test = new BigDecimal(srtTest);//26行出错
        System.out.println(srtTest);
        System.out.println(test);

运行结果图:
BigDecimal构造方法两个小数点异常

2.出现不为数字,也不是e的字符

        String srtTest = "123q123";
        BigDecimal test = new BigDecimal(srtTest);//26行出错
        System.out.println(srtTest);
        System.out.println(test);

运行结果图:
BigDecimal构造方法字符异常
(因为异常信息过长省略了一点点)

3.数字过大越界

        String srtTest = "4294967296e4294967296";//4294967296 = 2的32次方
        BigDecimal test = new BigDecimal(srtTest);//26行出错
        System.out.println(srtTest);
        System.out.println(test);

运行结果图:
BigDecimal数字过大异常

除了单个参数的构造方法,还有与char[]类型有关的三个参数的构造方法,其中另外两个参数的offset是第一个要考虑的下标,len是长度,下面是示例:

        char[] charTest = {'1','2','3','4','5'};
        BigDecimal bdtest1 = new BigDecimal(charTest,2,2);
        System.out.println("bdtest1 = " + bdtest1);

之后是结果图示:
BigDecimal三个参数构造方法

有MathContext的构造方法

我们不难从api的图中发现,很多构造方法都有MathContext这个类的对象,那么他到底是什么呢?我们先研究一下这个MathContext。

什么是MathContext

MathContext在api中的介绍
我们可以通过api的描述得知,这是一个不可变对象,我们再来看看它的构造方法:
MathContext的构造方法
通过描述我们可以得知,这个int类型的setPrecision是精度,用来描述多少位数,并且这个数是非负的,除此之外,我们还发现了一个叫做RoundingMode的东西,我们也来研究一下。

RoundingMode的api描述

通过这个api的图我们也能看懂一点点这个东西是啥,但是下面的这一串乱码,应该是机翻翻不动了导致的吧…
看了这个介绍之后我们发现这是一种枚举类型,那么他都有哪些值呢:
RoundingMode的枚举值
这一下通过描述我们大概就明白了,MathContext通过这个RoundingMode来决定舍入的模式,如果不做特殊的要求,默认情况下的是HALF_UP模式,也就是需要舍入时,判断这个数等于最近的满足精度要求的数,如果有两个满足精度要求的数距离需要舍入的数相同,那么选择更大的那个数,我们可以通过下面的例子来了解:

        double doubleTest1 = 11.55;
        double doubleTest2 = 11.54;
        MathContext mcTest = new MathContext(3);
        BigDecimal bdtest1 = new BigDecimal(doubleTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(doubleTest2,mcTest);
        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);

结果图示:
BigDecimal通过MathContext构造

这是使用默认形式的RoundingMode来执行的结果,下面我尝试采用不同形式的RoundingMode来尝试着构造不同的MathContext,再构造BigDecimal

不同RoundingMode下的MathContext

1.CEILING

        //CEILING是向正无穷取值
        RoundingMode rmTest = RoundingMode.CEILING;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);

结果图示:
CEILING模式的BigDecimal

2.DOWN

        //DOWN是向0取值
        RoundingMode rmTest = RoundingMode.DOWN;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);

结果图示:
DOWN模式的BigDecimal

3.FLOOR

        //FLOOR是向负无穷大舍入
        RoundingMode rmTest = RoundingMode.FLOOR;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);

结果图示:
FLOOR模式BigDecimal

4.HALF_DOWN

        //HALF_DOWN是最近舍入,如果相同大小,则向下舍入
        RoundingMode rmTest = RoundingMode.HALF_DOWN;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);

结果图示:
HALF_DOWN模式的BigDecimal

5.HALF_EVEN

        //HALF_EVEN是最近舍入,如果相同大小,则向偶数舍入
        RoundingMode rmTest = RoundingMode.HALF_EVEN;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        double numTest7 = 3.5;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);
        BigDecimal bdtest7 = new BigDecimal(numTest7,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);
        System.out.println("bdtest7 = " + bdtest7);

结果图示:
HALF_EVEN模式BigDecimal

6.HALF_UP
这一种也是不加RoundingMode时默认的模式

        //HALF_UP是最近舍入,如果相同大小,则向向上舍入
        RoundingMode rmTest = RoundingMode.HALF_UP;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        double numTest7 = 3.5;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);
        BigDecimal bdtest7 = new BigDecimal(numTest7,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);
        System.out.println("bdtest7 = " + bdtest7);

结果图示:
HALF_UP模式BigDecimal

7.UNNECESSARY

        //UNNECESSARY是要求数字不用舍入,如果需要舍入,则报异常
        RoundingMode rmTest = RoundingMode.UNNECESSARY;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2;
        double numTest2 = 2.0;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);

正确时的图示:
UNNECESSARY模式的BigDecimal

这种模式下会出现一种异常,因为要求数字是精确的
如果不精确他就会出现这样一个异常java.lang.ArithmeticException: Rounding necessary
代码例子如下:

        //UNNECESSARY是要求数字不用舍入,如果需要舍入,则报异常
        RoundingMode rmTest = RoundingMode.UNNECESSARY;
        MathContext mcTest = new MathContext(1,rmTest);
        //此时numTest1数据不合标准,是不精确的数据
        double numTest1 = 2.1;

        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);//75行

        System.out.println("bdtest1 = " + bdtest1);

结果图示:
UNNECESSARY模式下的异常

8.UP

        //UP是舍入时 数值变化为绝对值更大的那个满足要求的数
        RoundingMode rmTest = RoundingMode.UP;
        MathContext mcTest = new MathContext(1,rmTest);
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        double numTest7 = 3.5;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);
        BigDecimal bdtest7 = new BigDecimal(numTest7,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);
        System.out.println("bdtest7 = " + bdtest7);

结果图示:
UP模式的BigDecimal

特殊MathContext的构造方法

最后这一种通过String类型构造MathContext的方法,仅仅通过看api是无法完全理解的,或者说是看不懂的,我找到了这一部分代码的源码,如下所示:

    /**
     * Constructs a new {@code MathContext} from a string.
     *
     * The string must be in the same format as that produced by the
     * {@link #toString} method.
     *
     * <p>An {@code IllegalArgumentException} is thrown if the precision
     * section of the string is out of range ({@code < 0}) or the string is
     * not in the format created by the {@link #toString} method.
     *
     * @param val The string to be parsed
     * @throws IllegalArgumentException if the precision section is out of range
     * or of incorrect format
     * @throws NullPointerException if the argument is {@code null}
     */
    public MathContext(String val) {
        boolean bad = false;
        int setPrecision;
        if (val == null)
            throw new NullPointerException("null String");
        try { // any error here is a string format problem
            if (!val.startsWith("precision=")) throw new RuntimeException();
            int fence = val.indexOf(' ');    // could be -1
            int off = 10;                     // where value starts
            setPrecision = Integer.parseInt(val.substring(10, fence));

            if (!val.startsWith("roundingMode=", fence+1))
                throw new RuntimeException();
            off = fence + 1 + 13;
            String str = val.substring(off, val.length());
            roundingMode = RoundingMode.valueOf(str);
        } catch (RuntimeException re) {
            throw new IllegalArgumentException("bad string format");
        }

        if (setPrecision < MIN_DIGITS)
            throw new IllegalArgumentException("Digits < 0");
        // the other parameters cannot be invalid if we got here
        precision = setPrecision;
    }

可以看到它大概的意思是通过我们输入的String类型的数据区构造一个MathContext。
通过详细的阅读源码之后我们发现,他要求我们输入的参数String必须格式为

"precision=num roundingMode=xxx"

num必须为一个描述精度的int类型的数字,xxx必须为前面我们提到的RoundingMode中的8个模式之一才能执行,而且中间必须由空格隔开,否则他都会报错。
首先,我们先看一看正确格式的String类型输入的成功案例:

        //借用之前的UP模式才试验一下
        MathContext mcTest = new MathContext("precision=1 roundingMode=UP");
        double numTest1 = 2.4;
        double numTest2 = 2.5;
        double numTest3 = 2.6;
        double numTest4 = -2.4;
        double numTest5 = -2.5;
        double numTest6 = -2.6;
        double numTest7 = 3.5;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        BigDecimal bdtest2 = new BigDecimal(numTest2,mcTest);
        BigDecimal bdtest3 = new BigDecimal(numTest3,mcTest);
        BigDecimal bdtest4 = new BigDecimal(numTest4,mcTest);
        BigDecimal bdtest5 = new BigDecimal(numTest5,mcTest);
        BigDecimal bdtest6 = new BigDecimal(numTest6,mcTest);
        BigDecimal bdtest7 = new BigDecimal(numTest7,mcTest);

        System.out.println("bdtest1 = " + bdtest1);
        System.out.println("bdtest2 = " + bdtest2);
        System.out.println("bdtest3 = " + bdtest3);
        System.out.println("bdtest4 = " + bdtest4);
        System.out.println("bdtest5 = " + bdtest5);
        System.out.println("bdtest6 = " + bdtest6);
        System.out.println("bdtest7 = " + bdtest7);

结果图示:
String类型做MathContext参数的BigDecimal构造

可以对比发现,和之前直接使用UP模式和确定精度为1时一样。

然后我们再试验一种错误的方法,看一下它的异常提示:

        //这里我们用”,“隔开而不是用空格隔开来试验一下
        MathContext mcTest = new MathContext("precision=1,roundingMode=UP");
        double numTest1 = 2.4;
        BigDecimal bdtest1 = new BigDecimal(numTest1,mcTest);
        System.out.println("bdtest1 = " + bdtest1);

结果图示:
bad String format
bad String format!!
如果不按照他给出的格式输入的话就会出现这个异常提示。

好了,以上就是现阶段BigDecimal的构造方法介绍了,其实还有一种BigInteger的方法没有介绍,因为对BigInteger的了解还不够,所以在介绍BigInteger时再回过头来讲一讲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值