为什么 Double::compareTo 可以用作 Stream.max(Comparator<? super T> comparator) 的参数

Why Double::compareTo can be used as an argument of Stream.max(Comparator<? super T> comparator)

Stream.max 的 api 需要一个类型为 Comparator<? super T> 的参数,而对于 Comparator,唯一的抽象方法是

int compare(T o1, T o2)

但是Double::compareTocompareToapi是

public int compareTo(Double anotherDouble)

为什么只提供一个参数,那么为什么Double::compareTo可以用作Stream

的参数
Optional<T> max(Comparator<? super T> comparator)

查看 oracle documentation。这是对 instance 方法的引用。这意味着,它可以被认为是 BiFunction,它将实例作为第一个参数。

Java Language Specification (15.13.3) 中我们可以读到:

If the form is ReferenceType :: [TypeArguments] Identifier, the body of the invocation method similarly has the effect of a method invocation expression for a compile-time declaration which is the compile-time declaration of the method reference expression. Run-time evaluation of the method invocation expression is as specified in §15.12.4.3, §15.12.4.4, and §15.12.4.5, where:

  • The invocation mode is derived from the compile-time declaration as specified in §15.12.3.

  • If the compile-time declaration is an instance method, then the target reference is the first formal parameter of the invocation method. Otherwise, there is no target reference.

  • If the compile-time declaration is an instance method, then the arguments to the method invocation expression (if any) are the second and subsequent formal parameters of the invocation method. Otherwise, the arguments to the method invocation expression are the formal parameters of the invocation method.

有趣的部分是我加粗的

下面MyComparator实现一个Comparator。它有两个参数。
它与 lambda 表达式相同 (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);
   }
}