Метод 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
.