Почему Stream.max принимает Integer.compare в качестве входного параметра? - PullRequest
0 голосов
/ 20 февраля 2019

Метод stream.max использует Comparator, но Integer.compare не реализует интерфейс Comparator.Единственное сходство заключается в том, что они имеют одну и ту же сигнатуру метода метода compare ().Так что я не совсем понимаю, каковы предпосылки для того, чтобы стать входным параметром Comparator?Спасибо.

Пример:

List<Integer> ls = Arrays.asList(9,2,5,8); 
System.out.println(ls.stream().max(Integer::compare).get());

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

Интерфейс Comparator является функциональным интерфейсом, поэтому можно использовать любое лямбда-выражение или ссылку на метод, сигнатура метода которого соответствует функциональному интерфейсу.

Метод compare принимаетдва объекта, сравнивает их и возвращает int для целей заказа.Ссылка на метод Integer::compare ссылается на Integer s compare метод , и сигнатура этого метода совпадает, поэтому компилятор разрешает этой ссылке метода разрешить экземпляр Comparator.

Лямбда-выражения и ссылки на методы допускаются при передаче в качестве аргумента методу, присвоении переменной и в качестве аргумента оператору приведения.Здесь ваша ссылка на метод передается методу в качестве аргумента, поэтому компилятор видит это как допустимый код.

0 голосов
/ 20 февраля 2019

Integer.compare(int, int) имеет подпись, которую мы можем использовать для реализации Comparator<Integer>.compare(Integer, Integer).Поскольку Comparator является функциональным интерфейсом, мы можем использовать ссылку на метод Integer.compare для предоставления реализации Comparator<Integer>.

В этой форме используется метод static Integer.compare(int, int).В этом случае, когда поток сравнивает два элемента, он выполняет следующий статический вызов:

Integer.compare(element1, element2);

Integer::compare может использоваться для обеспечения реализации любого функционального интерфейса с такой же сигнатурой, например,:

BinaryOperator<Integer> bo = Integer::compare; //int functName(int, int)
BiFunction<Integer, Integer, Integer> bf = Integer::compare;

//or even
BiConsumer<Integer, Integer> bc = Integer::compare; //return value ignored

Другая форма ссылки на ваш метод должна использовать:

System.out.println(ls.stream().max(Integer::compareTo).get());

В этом случае для сравнения двух элементов поток вызывает:

element1.compareTo(element2);

Во второй форме используется вариант экземпляра integer.compareTo(otherInteger) (фактические экземпляры, используемые в качестве цели и параметра, разрешаются во время выполнения, когда поток сравнивает элементы два в два в этом случае).Это основано на:

JLS-15.13.3 Оценка времени выполнения ссылок на методы :

Если форма имеет идентификатор ReferenceType :: [TypeArguments], тело метода вызова аналогично имеет эффект выражения вызова метода для объявления времени компиляции, которое является объявлением времени компиляции выражения ссылки на метод ......

  • Если объявление времени компиляции является методом экземпляра, то целевая ссылка является первым формальным параметром метода вызова.В противном случае нет целевой ссылки.

  • Если объявление времени компиляции является методом экземпляра, то аргументами выражения вызова метода (если они есть) являются второй и последующие формальные параметрыметода вызова.В противном случае аргументы выражения вызова метода являются формальными параметрами метода вызова.

Описание деталей того, как ссылки на метод разрешаются, проверяются и вызывают, будетслишком много, чтобы быть включенным сюда, так что, безусловно, хорошая идея пройти этот раздел JLS: -)

0 голосов
/ 20 февраля 2019

Поскольку в этом контексте Integer::compare эквивалентно его лямбда-форме:

(a, b) -> Integer.compare(a, b)

И эта лямбда-форма также логически эквивалентна своей анонимной форме класса:

new Comparator<Integer>() {
    @Override
    public int compare(Integer a, Integer b) {
        return Integer.compare(a, b);
    }
}
...