Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why it works: BigDecimal Sum with Reduce and BigDecimal::add

I can understand why Total1 is calculated, but as Total2 is calculated I have no idea! How can a BigDecimal::add be used in a BiFunction? Signatures are not the same !!!

package br.com.jorge.java8.streams.bigdecimal;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class BigDecimalSumTest {
    public static void main(String[] args) {

        List<BigDecimal> list = new ArrayList<>();

        list.add(new BigDecimal("1"));
        list.add(new BigDecimal("2"));

        BigDecimal total1 = list.stream().reduce(BigDecimal.ZERO, (t, v) -> t.add(v));

        BigDecimal total2 = list.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

        System.out.println("Total 1: " + total1);
        System.out.println("Total 2: " + total2);
    }
}
like image 264
Eng Jorge Augusto Corra dos Re Avatar asked Dec 31 '18 03:12

Eng Jorge Augusto Corra dos Re


2 Answers

Its used as a BinaryOperator<T> in your current context.

Its equivalent lambda representation:

(bigDecimal, augend) -> bigDecimal.add(augend) // same as in your previous line of code

and anonymous class representation:

new BinaryOperator<BigDecimal>() {
    @Override
    public BigDecimal apply(BigDecimal bigDecimal, BigDecimal augend) {
        return bigDecimal.add(augend);
    }
}

where BinaryOperator<T> extends BiFunction<T,T,T>, meaning its a specialization of BiFunction for the case where the operands and the result are all of the same type.

Added to that, your code is actually using one of the overloaded implementations of reduce method i.e. Stream.reduce(T identity, BinaryOperator<T> accumulator).


How can a BigDecimal::add be used in a BiFunction

Just a step further and only for explanation, there is also an overloaded implementation that uses combiner as in Stream.reduce​(U identity, BiFunction<U,​? super T,​U> accumulator, BinaryOperator<U> combiner) which would look like :

BigDecimal total = list.stream()
                       .reduce(BigDecimal.ZERO, BigDecimal::add, BigDecimal::add);
//                                                   ^^                ^^
//                                              BiFunction here    BinaryOperator here
like image 120
Naman Avatar answered Sep 20 '22 00:09

Naman


Given BigDecimal::add is being used as a BiFunction<BigDecimal, BigDecimal, BigDecimal>, the compiler will look for one of two eligible signatures.

The first possible signature, as you have picked up on, would be a two-argument static method. The relevant lambda would be (a, b) -> BigDecimal.add(a, b). Of course, you are correct to recognise that this doesn't exist.

The second possible signature would be a one-argument instance method. The equivalent lambda here would be (a, b) -> a.add(b). As this one exists and the other does not, this is how the compiler would interpret it.

like image 25
Joe C Avatar answered Sep 21 '22 00:09

Joe C