14

The Stream.reduce method takes a BinaryOperator as an argument. The function signature of a BinaryOperator is (T,T) -> T. The BigDecimal::min method has only 1 parameter in its method signature (ie. (T) -> T ).

Why doesn't the compiler complain when I pass BigDecimal::min to the Stream.reduce method?

Sample code:

List<BigDecimal> bigDecimalList = new ArrayList<>();
        bigDecimalList.add(BigDecimal.valueOf(1));
        bigDecimalList.add(BigDecimal.valueOf(2));
        bigDecimalList.add(BigDecimal.valueOf(3));
BigDecimal minResult = bigDecimalList.stream().reduce(BigDecimal::min).orElse(BigDecimal.ZERO);

Thanks.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Jeffrey Sze
  • 141
  • 3
  • 3
    I'd have to guess but since `BigDecimal min(BigDecimal o)` is an instance method and thus internally the method actually has the signature `BigDecimal min(this, BigDecimal o)` it matches the requirements for `BinaryOperator`. – Thomas Mar 31 '17 at 08:57
  • 2
    http://stackoverflow.com/q/22516331/2711488 – Holger Mar 31 '17 at 11:40

2 Answers2

19

This is actually called Reference to an instance method of an arbitrary object of a particular type.

The compiler takes the calling instance as the first argument and as such these are equivalent:

    BinaryOperator<BigDecimal> b = (left, right) -> left.min(right);

    BinaryOperator<BigDecimal> b2 = BigDecimal::min;
    b2.apply(left, right);

Things are much funner IMO when you have something like this:

@FunctionalInterface
interface TriFunction<A, B, C, R> {

    R apply(A a, B b, C c);

}

and a theoretical class:

class Test {

    int x;

    int y;

    public Test(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Test copy(int n, int m) {
        return new Test(m, n);
    }
}

Then you could write something like this:

  TriFunction<Test, Integer, Integer, Test> f = Test::copy;

  TriFunction<Test, Integer, Integer, Test> f2 = 
           (test, i, j) -> test.copy(i, j);
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • `n` and `m` got swapped, and it's bugging me... Great answer! – 4castle Mar 31 '17 at 17:58
  • @JeffreySze if this answer helped you could accept it. https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Eugene May 14 '17 at 08:16
8

Because BigDecimal::min is an instance method. Javac is smart enough to turn it into a (T, T) -> T if you use BigDecimal::min. The first paramter passed to the resulting BinaryOperator will be the instance and the second will be the parameter of min (though in BinaryOperator's case it is required that the order can be reversed). It will be (T) -> T if you use something like new BigInteger(1)::min.

glee8e
  • 6,180
  • 4
  • 31
  • 51