关于使用Java BigDecimal保证精度以及整合spring boot查询添加账单小案例

30 篇文章 0 订阅
24 篇文章 1 订阅

前言

近期做到项目是有关金额这一块,虽然只是记录,而且对要求精度不是那么高。不够平时基本没用过,所以还是尝试使用了BigDecimal。当然其实可以用double类型不够,然后使用工具类进行相对精确的计算。下面会放上一些工具类。

关于Java详解的有相关的文章,我有一篇不错的已经转载下来地址可回看:
https://blog.csdn.net/xtho62/article/details/112307091

1.Javabean对应数据库类型

因为肯定涉及到数据库的操作,所以先看看java类型和字段属性对应管理
(以下是MySQL为例)

类型名称显示长度数据库类型JAVA类型JDBC类型索引(int)
VARCHARL+NVARCHARjava.lang.String12
CHARNCHARjava.lang.String1
BLOBL+NBLOBjava.lang.byte[]-4
TEXT65535VARCHARjava.lang.String-1
INTEGER4INTEGER UNSIGNEDjava.lang.Long4
TINYINT3TINYINT UNSIGNEDjava.lang.Integer-6
SMALLINT5SMALLINT UNSIGNEDjava.lang.Integer5
MEDIUMINT8MEDIUMINT UNSIGNEDjava.lang.Integer4
BIT1BITjava.lang.Boolean-7
BIGINT20BIGINT UNSIGNEDjava.math.BigInteger-5
FLOAT4+8FLOATjava.lang.Float7
DOUBLE22DOUBLEjava.lang.Double8
DECIMAL11DECIMALjava.math.BigDecimal3
BOOLEAN1同TINYINT
ID11PK (INTEGER UNSIGNED)java.lang.Long4
DATE10DATEjava.sql.Date91
TIME8TIMEjava.sql.Time92
DATETIME19DATETIMEjava.sql.Timestamp93
TIMESTAMP19TIMESTAMPjava.sql.Timestamp93
YEAR4YEARjava.sql.Date91

对于bolb,一般用于对图片的数据库存储,原理是把图片打成二进制,然后进行的一种存储方式,在java中对应byte[]数组。


对于boolen类型,在mysql数据库中,个人认为用int类型代替较好,对bit操作不是很方便,尤其是在具有web页面开发的项目中,表示0/1,对应java类型的Integer较好。


decimal列的声明语法是decimal(m,d)。


在mysql5.1中,参数的取值范围:
1、M是数字的最大数(精度)。其范围为1~65(在较旧的MySQL版本中,允许的范围是1~254)。
2、D是小数点右侧数字的数目(标度)。其范围是0~30,但不得超过M。
说明:float占4个字节,double占8个字节,decimail(M,D)占M+2个字节。
如DECIMAL(5, 2) 的最大值为9 9 9 9 . 9 9,因为有7 个字节可用。

像我们的单笔账单大多数情况下不超过亿可以使用DECIMAL(10,2)

可参考:https://blog.csdn.net/defonds/article/details/46681701

2.工具类

2.1封装BigDecimal比较的工具类

import java.math.BigDecimal;

public final class DecimalUtils {

    private final BigDecimal value;

    public DecimalUtils(BigDecimal value) {
        this.value = value;
    }

    public static DecimalUtils of(BigDecimal value) {
        return new DecimalUtils(value);
    }

    // 小于
    public boolean lt(BigDecimal val) {
        return value.compareTo(val) == -1;
    }

    // 等于
    public boolean eq(BigDecimal val) {
        return value.compareTo(val) == 0;
    }

    // 大于
    public boolean gt(BigDecimal val) {
        return value.compareTo(val) == 1;
    }

    // 大于等于
    public boolean ge(BigDecimal val) {
        return value.compareTo(val) > -1;
    }

    // 小于等于
    public boolean le(BigDecimal val) {
        return value.compareTo(val) < 1;
    }
}

调用示例:

BigDecimal a = new BigDecimal("0.02");
BigDecimal b = new BigDecimal("0.01");
boolean bool = Decimal.of(a).ge(b);

2.2封装计算的工具类(使用浮点数的方法)

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 精确的浮点数运算
 * 
 * @author ruoyi
 */
public class Arith
{

    /** 默认除法运算精度 */
    private static final int DEF_DIV_SCALE = 10;

    /** 这个类不能实例化 */
    private Arith()
    {
    }

    /**
     * 提供精确的加法运算。
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1, double v2)
    {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2)
    {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2)
    {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * 小数点以后10位,以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1, double v2)
    {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale)
    {
        if (scale < 0)
        {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        if (b1.compareTo(BigDecimal.ZERO) == 0)
        {
            return BigDecimal.ZERO.doubleValue();
        }
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理。
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    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 = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
    }
}

而BigDecimal直接调用Java提供的Api即可!!!

3.常见报错以及处理

1.除法不一定能整除

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result异常的解决方法

先说一下为什么会有这个异常,其实是因为计算中,有时候我们会使用除法,但是值得注意的是我们的除法并不是都可以整除。所以我们调用方法的是时候应该使用带有保留位数,以及有小数处理的方法,而不是直接两个数字相除!!!!!
在这里插入图片描述
其中2是保留即为两位小数,而后面的则是四舍五入的处理方法。

2.分母不能为0!!!!!!

4.整合spring boot查询添加账单小案例

附上整合spring boot使用spring data jpa查询添加账单的小案例:
https://gitee.com/calmtho/springboot/tree/master/boot_jpa

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值