Почему Double :: compareTo можно использовать в качестве аргумента Stream.max (Comparator компаратор) - PullRequest
4 голосов
/ 15 февраля 2020

API для Stream.max требует аргумент типа Comparator<? super T>, а для Comparator единственным абстрактным методом является

int compare(T o1, T o2)

, но Double::compareTo, API compareTo равен

public int compareTo(Double anotherDouble)

зачем просто указывать один аргумент, и почему Double::compareTo может использоваться в качестве аргумента Stream

Optional<T> max(Comparator<? super T> comparator)

Ответы [ 3 ]

11 голосов
/ 15 февраля 2020

Ознакомьтесь с oracle документацией . Это ссылка на метод instance . Это означает, что его можно рассматривать как BiFunction, который принимает экземпляр в качестве первого аргумента.

В Java Спецификация языка (15.13.3) мы можем прочитать, что:

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

  • Режим вызова определяется из Объявление времени компиляции, как указано в §15.12.3.

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

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

Интересная часть выделена мной.

2 голосов
/ 15 февраля 2020

Ниже MyComparator реализует Comparator. Он принимает два аргумента.
Это то же самое, что и лямбда-выражение (d1,d2) -> d1.compareTo(d2)
, и то же самое, что и ссылка на метод Double::compareTo

Ссылка на метод такая же, потому что d1 является Double, поэтому Java предполагает, что метод compareTo должен быть вызван на первом Double. Другой аргумент d2 становится аргументом для вызываемого метода. @ Andronicus также очень хорошо это объясняет.

3 варианта в этом примере эквивалентны:

import java.util.List;
import java.util.Comparator;

class MyComparator implements Comparator<Double> {
  public int compare(Double d1, Double d2) {    // (d1,d2) ->
    return d1.compareTo(d2);                    // d1.compareTo(d2)
  }
}

public class Testing {
    public static void main(String[] args) {
      List<Double> list = List.of(1.1,2.2,3.3,4.4,5.5,6.6,7.7);

      Double maxClass =
        list.stream()
            .max(new MyComparator())
            .orElse(Double.NEGATIVE_INFINITY);

      Double maxLamdba =
        list.stream()
            .max((d1,d2) -> d1.compareTo(d2))
            .orElse(Double.NEGATIVE_INFINITY);

      Double maxMethodreference =
        list.stream()
            .max(Double::compareTo)
            .orElse(Double.NEGATIVE_INFINITY);
   }
}
0 голосов
/ 15 февраля 2020

вы можете использовать один из этих двух методов для сравнения Double

listOfDouble.stream().max(Double::compareTo);
listOfDouble.stream().max(Comparator.naturalOrder());
...