java知识点:BigDecimal:金额相关的计算、打印以及compareto比较和BigDecimal过时方法的替换方案

目录

BigDecimal:金额相关

BigDecimal数字数据转String文本,避免输出科学计数法

 ​

附 java中的compareto方法

list排序

treeMap 中(基于key的排序)

TreeMap的按value排序

过时方法说明:BigDecimal.ROUND_HALF_UP

替换方案:java.math.RoundingMode


BigDecimal:金额相关

BigDecimal 是java小数操作的一个专有类,在电商、金融行业 存储跟金额有关的字段

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算,双精度浮点型变量double可以处理16位有效数。不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度,在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象

     BigDecimal a = new BigDecimal(5);
     BigDecimal b = new BigDecimal(40);
     BigDecimal add = a.add(b); // +
     BigDecimal subtract = a.subtract(b); // -
     BigDecimal multiply = a.multiply(b); // *

     BigDecimal divide = a.divide(b); // \
     BigDecimal result5 = num2.divide(num1, 20, BigDecimal.ROUND_HALF_UP)//(已过时)后面说明,第二个参数为保留几位小数,➗务必写成这种,防止异常java.lang.ArithmeticException

     BigDecimal result4 = num3.abs(); //绝对值
        
注意:  System.out.println()中的数字默认是double类型的,double类型小数计算不精准。
        使用BigDecimal类构造方法传入double类型时,计算的结果也是不精确的!


取整:
BigDecimal bd = new BigDecimal("12.1");
long l  = bd.setScale( 0, BigDecimal.ROUND_UP ).longValue(); // 向上取整
long l  = bd.setScale( 0, BigDecimal.ROUND_DOWN ).longValue(); // 向下取整

BigDecimal b = new BigDecimal("2.225667").setScale(2, BigDecimal.ROUND_DOWN);
//b = 2.22 直接去掉多余的位数

BigDecimal c = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_UP);
//c = 2.23 跟上面相反,进位处理

因为不是所有的浮点数都能够被精确的表示成一个double 类型值,有些浮点数值不能够被精确的表示成 double 类型值,因此它会被表示成与它最接近的 double 类型的值。必须改用传入String的构造方法。这一点在BigDecimal类的构造方法注释中有说明

//尽量用字符串的形式初始化
    BigDecimal num12 = new BigDecimal("0.005");
    BigDecimal num12 = new BigDecimal(Double.toString(d));
    BigDecimal num12 = BigDecimal.valueOf(1.010);
    // 使用string类型额构造函数进行构造时,equals无法比较,比如多余的0
    // compareTo方法则只会进行大小的比较,与精度无关:1.010=1.01为true

     compareTo返回为正数表示a1>a2, 返回为负数表示a1<a2, 返回为0表示a1==a2;
    //        c=1.010 ,b=1.01, c.compareTo(b) = 0  //b c 都是BigDecimal类型
    // 使用valueof方法进行构造时,他会帮我们去掉多余的精度可以用equals比较
    //        c.equals(b)  = true

BigDecimal 精度描述:

模式               描述
CEILING        正无穷大方向取整
FLOOR          负无穷大方向取整
DOWN           向 0 的方向取整
UP                 正数向正无穷大取整,负数向负无穷大取整
HALF_UP          5,6,7,8,9 向上取整、 1,2,3,4 向下取整、 常用的4舍5入
HALF_DOWN    6,7,8,9 向上取整 1,2,3,4,5 向下取整
HALF_EVEN     小数位是5时,判断整数部分是奇数就进位、 小数位是5时,判断整数部分是偶数就舍弃、
                           1,2,3,4, 舍弃、 6,7,8,9, 进位


常用方法PS
currency = NumberFormat.getCurrencyInstance();    //建立货币格式化引用
NumberFormat percent = NumberFormat.getPercentInstance();     //建立百分比格式化用
percent.setMaximumFractionDigits(3);               //百分比小数点最多3位

currency.format(bigLoanAmount)
percent.format(bigInterestRate)
currency.format(bigInterest)

BigDecimal数字数据转String文本,避免输出科学计数法

直接返回给前端的话11.00会显示为11,

// 浮点数的打印
System.out.println(new BigDecimal("10000000000").toString());

// 普通的数字字符串
System.out.println(new BigDecimal("100.000").toString());

// 去除末尾多余的0
System.out.println(new BigDecimal("100.000").stripTrailingZeros().toString());

// 避免输出科学计数法
System.out.println(new BigDecimal("100.000").toPlainString());

// 四舍五入,保留两位小数,避免输出科学计数法
System.out.println(new BigDecimal("100.000").setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()); // 方法已过时,说明更新在下方
System.out.println(new BigDecimal("100.000").setScale(2));
System.out.println(new BigDecimal("100.000").setScale(2, RoundingMode.HALF_UP));

 

java.math.RoundingMode 几个参数详解

RoundingMode.CEILING:取右边最近的整数
RoundingMode.DOWN:去掉小数部分取整,也就是正数取左边,负数取右边,相当于向原点靠近的方向取整
RoundingMode.FLOOR:取左边最近的正数
RoundingMode.HALF_DOWN:五舍六入,负数先取绝对值再五舍六入再负数
RoundingMode.HALF_UP:四舍五入,负数原理同上
RoundingMode.HALF_EVEN:这个比较绕,整数位若是奇数则四舍五入,若是偶数则五舍六入

附 java中的compareto方法

返回为正数表示a1>a2, 返回为负数表示a1<a2, 返回为0表示a1==a2;

除了基本类型(< = >);Date、String、Integer、或者其他的,可以直接使用compareTo比较

  • 返回参与比较的前后两个字符串的asc码的差值,如果两个字符串首字母不同,则该方法返回首字母的asc码的差值

 

String a1 = "a";
String a2 = "c";
System.out.println(a1.compareTo(a2));//结果为-2
  • 参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的asc码差值

 

String a1 = "aa";
String a2 = "ad";
System.out.println(a1.compareTo(a2));//结果为-3
  • 如果两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值

 

String a1 = "aa";
String a2 = "aa12345678";
System.out.println(a1.compareTo(a2));//结果为-8
  • compareToIgnoreCase忽略大小写
  • Comparable<T>接口中的compareTo
compareTo方法内必须做非空判断(规范问题),当然int类型就不用了。
1、模型必须实现Comparable<T>接口
2、Collection.sort(list)会自动调用compareTo,如果没有这句,list是不会排序的,也不会调用compareTo方法
3、如果是数组则用Arrays.sort(a)方法

// 实体类重写
@Override
public int compareTo(Book o) {
    // TODO Auto-generated method stub
    //return this.bookPrice-o.bookPrice;//按价格排序 升序
    //return o.bookPrice-this.bookPrice;//按价格排序 降序
    //return this.bookName.compareTo(o.bookName);//按书名排序 升序
    //先按 id 再按价格 最后按书名排序 升序
    int result = this.bookId - o.bookId;
    if(result == 0){
        result =this.bookPrice - o.bookPrice;
    }
    if(result == 0){
        result = this.bookName.compareTo(o.bookName);
    }
    return result;
}
// 使用
Collections.sort(books);

list排序

// JDK1.8以前的老用法,之前一直这样写
Collections.sort(books,new Comparator<Book>() {

            @Override
            public int compare(Book o1, Book o2) {
                // TODO Auto-generated method stub
                
                return o1.getBookPrice() - o2.getBookPrice();
                
            }
        });

// JDK1.8
Collections.sort(books,(Book a, Book b) -> { return a.getBookPrice()-b.getBookPrice(); });

// 简写1
Collections.sort(books,(Book a, Book b) ->  a.getBookPrice()-b.getBookPrice());
// 简写2
Collections.sort(list, Comparator.comparingInt(Channel::getChnumber));

treeMap 中(基于key的排序)

treeMap默认的是基于key的从小到大 的排列
自定义排序也是基于key的,如果key object类型 可以自定义各种排序

TreeMap<String, Person> treeMap = new TreeMap<>((String a,String b)-> b.compareTo(a));//降序
TreeMap<String, Person> treeMap = new TreeMap<>((String a,String b)-> a.compareTo(b));//升序

TreeMap的按value排序

(转换成entry list 然后排序)汉字是按ascii码排序的,不是汉语拼音

User p1 = new User(1, "A小红");
User p2 = new User(5, "D赵明");
User p3 = new User(2, "W孙宇");
User p4 = new User(9, "C黎明");

TreeMap<String, User> treeMap = new TreeMap<>();

treeMap.put("45", p1);
treeMap.put("12", p2);
treeMap.put("85", p3);
treeMap.put("33", p4);


List<Map.Entry<String, User>> entries = new ArrayList<>(treeMap.entrySet());

Collections.sort(entries,
        (Map.Entry<String, User> e1, Map.Entry<String, User> e2) -> ((User) e1.getValue()).getUserName()
                .compareTo(((User) e2.getValue()).getUserName()));
System.out.println("按名字顺序排列");
for (Entry<String, User> entry : entries) {
    System.out.println(entry.getValue());

}

过时方法说明:BigDecimal.ROUND_HALF_UP

BigDecimal.ROUND_HALF_UP

BigDecimal中的过时方法:
ROUND_UP:舍入远离零的舍入模式,在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。此舍入模式始终不会减少计算值的大小。
ROUND_DOWN:接近零的舍入模式,在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。此舍入模式始终不会增加计算值的大小。
ROUND_CEILING:接近正无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;如果为负,则舍入行为与 ROUND_DOWN 相同。此舍入模式始终不会减少计算值。
ROUND_FLOOR:接近负无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;如果为负,则舍入行为与 ROUND_UP 相同。此舍入模式始终不会增加计算值。
ROUND_HALF_UP:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。这是我们大多数人在小学时就学过的舍入模式(四舍五入)。
ROUND_HALF_DOWN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。
ROUND_HALF_EVEN    银行家舍入法:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。如果前一位为奇数,则入位,否则舍去。以下例子为保留小数点1位,那么这种舍入方式下的结果。
1.15>1.2 1.25>1.2
ROUND_UNNECESSARY:断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

替换方案:java.math.RoundingMode

java.math.RoundingMode 几个参数详解

RoundingMode.CEILING:取右边最近的整数
RoundingMode.DOWN:去掉小数部分取整,也就是正数取左边,负数取右边,相当于向原点靠近的方向取整
RoundingMode.FLOOR:取左边最近的正数
RoundingMode.HALF_DOWN:五舍六入,负数先取绝对值再五舍六入再负数
RoundingMode.HALF_UP:四舍五入,负数原理同上
RoundingMode.HALF_EVEN:这个比较绕,整数位若是奇数则四舍五入,若是偶数则五舍六入

更多java常用知识点整理:https://blog.csdn.net/qq_44695727/article/details/101054712

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑶山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值