Метод BigDecimal # min квалифицируется как BinaryOperator?

Метод Stream.reduce принимает в качестве аргумента BinaryOperator. Функциональной сигнатурой a BinaryOperator является (T,T) -> T. Метод BigDecimal::min имеет только один параметр в своей сигнатуре метода (т.е. (T) -> T).

Почему компилятор не жалуется, когда я передаю BigDecimal::min методу Stream.reduce?

Пример кода:

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);

Спасибо.

Ответы

Ответ 1

На самом деле это называется ссылкой на метод экземпляра произвольного объекта определенного типа.

Компилятор принимает вызывающий экземпляр в качестве первого аргумента и как таковой эквивалентны:

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

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

Вещи намного более увлекают ИМО, когда у вас есть что-то вроде этого:

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

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

}

и теоретический класс:

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);
    }
}

Тогда вы могли бы написать что-то вроде этого:

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

  TriFunction<Test, Integer, Integer, Test> f2 = 
           (test, i, j) -> test.copy(i, j);

Ответ 2

Потому что BigDecimal::min - это метод экземпляра. Javac достаточно умен, чтобы превратить его в (T, T) -> T, если вы используете BigDecimal::min. Первым параметром, переданным в результирующий BinaryOperator, будет экземпляр, а второй будет параметром min (хотя в случае BinaryOperator требуется, чтобы порядок можно было отменить). Это будет (T) -> T, если вы используете что-то вроде new BigInteger(1)::min.