This is the fourth day of my participation in the Novembermore Challenge

preface

Recently, I am working on a module related to orders. There is an order list interface, and I need to sum the order amount. Each time you iterate through the list and take the sum using the Bigdecimal.add () method. It feels like a hassle. SummingInt, java8’s stream.collect, can be used to sum an int. See if you can sum BigDecimal from a stream of java8. The Sum that contains Collectors does not have an API. So you have to write a summingBigDecimal method like a copycat.

BigDecimal

Why BigDecimal? Why not use float and double? Briefly, floats and doubles are designed for scientific and engineering calculations. It provides fast and accurate calculations over a wide range of values. However, they do not provide completely accurate results, so they cannot be used in situations where precise results are required. However, commercial calculations require accurate results, which is where BigDecimal is needed.

For example

System. The out. Println (0.1 + 0.2);Copy the code

In fact, it is easy to know 0.3, but in fact, the program runs 0.30000000000000004. That’s because computers are binary, and the decimal place calculation works like this, multiplying by 2 repeatedly, taking the left part of the decimal point. If the product is greater than 1, subtract 1. Abbreviation: multiply the basis to round. Arrange the numbers to the left of the decimal point from left to right after each multiplication. All the way to zero. In the realm of money, using float and double is obviously inappropriate, so BigDecimal is generally used for calculations.

summingBigDecimal

Before implementing summingBigDecimal, take a look at how summingInt is implemented.

public static <T> Collector<T, ? , Integer> summingInt(ToIntFunction<? super T> mapper) { return new CollectorImpl<>( () -> new int[1], (a, t) -> { a[0] += mapper.applyAsInt(t); }, (a, b) -> { a[0] += b[0]; return a; }, a -> a[0], CH_NOID); }Copy the code

You can see that a collector is returned, and you need to pass in a function that extracts the attributes of the request and, T- the type of the input element. So to implement a BigDecimal sum, we simply change the Integer to BigDecimal. The applyAsInt interface is also used in the method, so we need to provide an applyAsBigDecimal as well.

@FunctionalInterface
public interface ToBigDecimalFunction<T> {
    BigDecimal applyAsBigDecimal(T value);
}
Copy the code

Finally, take a look at the source code for the summingBigDecimal implementation

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); }Copy the code