前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java之BigDecimal的高级使用

Java之BigDecimal的高级使用

作者头像
23号杂货铺
发布2019-09-26 17:31:05
1.3K0
发布2019-09-26 17:31:05
举报
文章被收录于专栏:23号杂货铺23号杂货铺

引入

使用Java开发的朋友,对于数据相关的计算想必都有过头疼的经历。float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。今天就分享一个关于小数精确计算的类(BigDecimal)高级用法。

1、加减乘除的简单封装;

2、引入Lambda表达式的聚合计算;

3、关于复杂对象的数组根据某一字段的值聚合计算;

0

2

撸代码

封装,是身为一个好程序猿的必备技能。往往通过一次封装之后的工具类,在使用起来会让人赏心悦目,心里那叫一个舒坦。

前提:Java8+(为了使用Lambda)

注意点:BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。

1、首先,是加减乘除。

代码语言:javascript
复制
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
 * 以double传参为例
 * 如果有各种嗜好,以在此基础上任意添加
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BigDecimalUtil {

    /**
     * 加
     */
    public static BigDecimal add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }

    /**
     * 减
     */
    public static BigDecimal sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2);
    }


    /**
     * 乘
     */
    public static BigDecimal mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2);
    }

    /**
     * 除,四舍五入保留2位小数
     */
    public static BigDecimal div(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 除,四舍五入保留n位小数
     */
    public static BigDecimal div(double v1, double v2, int n) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, n, BigDecimal.ROUND_HALF_UP);
    }
}

0

3

聚合计算

场景一:现在有一个User对象,需要计算所有User的总数money。

场景二:需要根据性别分组,计算不同性别的money总数。

User对象

代码语言:javascript
复制
import lombok.Data;
import java.math.BigDecimal;
/**
 * @Auther: bboyHan
 * @Date: 2019/1/18 18:10
 * @Description:
 */
@Data
public class User {
    private String name;
    private int gender; //1 - 男;2 - 女 0 - XXX
    private BigDecimal money;
}

2、引入Lambda表达式的聚合计算。(场景一)

代码语言:javascript
复制
//传统的求和,可能会是遍历list
‍BigDecimal rs = BigDecimal.ZERO;
List<BigDecimal> list = new ArrayList<>();
list.add(new BigDecimal("1"));
list.add(new BigDecimal("2"));
list.add(new BigDecimal("3"));
list.add(new BigDecimal("4"));
list.add(new BigDecimal("5"));
for (BigDecimal big : list) {
    rs = rs.add(big);
}‍

对于User这样的对象也可以照葫芦画瓢,通过foreach的方式add(user.getMoney)得到。

代码语言:javascript
复制
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
 * @Auther: bboyHan
 * @Date: 2019/1/18 18:27
 * @Description:
 */
public class BigdecimalTest {
    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三",1,new BigDecimal(10)));
        list.add(new User("老王",2,new BigDecimal(20)));
        list.add(new User("大佬",0,new BigDecimal(30)));
        BigDecimal rs = list.stream().map(User::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

3、复杂对象的分组求和。(场景二)

(1)新建CollectionsUtil

代码语言:javascript
复制
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class CollectorsUtil {
   static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
       private CollectorsUtil() {
   }

   @SuppressWarnings("unchecked")
   private static <I, R> Function<I, R> castingIdentity() {
      return i -> (R) i;
   }

   /**
    * Simple implementation class for {@code Collector}.
    *
    * @param <T>
    *            the type of elements to be collected
    * @param <R>
    *            the type of the result
    */
   static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
      private final Supplier<A> supplier;
      private final BiConsumer<A, T> accumulator;
      private final BinaryOperator<A> combiner;
      private final Function<A, R> finisher;
      private final Set<Characteristics> characteristics;
      CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
            Function<A, R> finisher, Set<Characteristics> characteristics) {
         this.supplier = supplier;
         this.accumulator = accumulator;
         this.combiner = combiner;
         this.finisher = finisher;
         this.characteristics = characteristics;
      }

      CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
            Set<Characteristics> characteristics) {
         this(supplier, accumulator, combiner, castingIdentity(), characteristics);
      }

      @Override
      public BiConsumer<A, T> accumulator() {
         return accumulator;
      }

      @Override
      public Supplier<A> supplier() {
         return supplier;
      }

      @Override
      public BinaryOperator<A> combiner() {
         return combiner;
      }

      @Override
      public Function<A, R> finisher() {
         return finisher;
      }

      @Override
      public Set<Characteristics> characteristics() {
         return characteristics;
      }
   }

   public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(ToBigDecimalFunction<? super T> mapper) {
      return new CollectorImpl<>(() -> new BigDecimal[1], (a, t) -> {
         if (a[0] == null) {
            a[0] = BigDecimal.ZERO;
         }
         a[0] = a[0].add(mapper.applyAsBigDecimal(t));
      }, (a, b) -> {
         a[0] = a[0].add(b[0]);
         return a;
      }, a -> a[0], CH_NOID);
   }
}

(2)新建ToBigDecimalFunction

代码语言:javascript
复制
import java.math.BigDecimal;
@FunctionalInterface
public interface ToBigDecimalFunction<T> {
   BigDecimal applyAsBigDecimal(T value);
}

(3)使用

代码语言:javascript
复制
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @Auther: bboyHan
 * @Date: 2019/1/18 18:29
 * @Description:
 */
public class BigdecimalTest {
    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User("张三", 1, new BigDecimal(10)));
        list.add(new User("老王", 2, new BigDecimal(20)));
        list.add(new User("大佬", 0, new BigDecimal(30)));
        Map<Integer, BigDecimal> rs = list.stream()
                .collect(
                        Collectors.groupingBy(User::getGender, CollectorsUtil.summingBigDecimal(User::getMoney))
                );
    }
}

0

4

小结

这么简单,就不总结了吧。拿出你的CV大法直接使用吧。

谢谢~

内容部分参考网上某大佬,记得好像是在云栖,不太记得了,在此鸣谢。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 23号杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档