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