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

时间:2020-02-15 15:12:41

标签: java java-8 java-stream comparator method-reference

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

int compare(T o1, T o2)

但是Double::compareTocompareTo的api是

public int compareTo(Double anotherDouble)

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

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

3 个答案:

答案 0 :(得分:10)

签出oracle documentation。这是对实例方法的引用。这意味着,可以将其视为BiFunction,它将实例作为第一个参数。

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

如果格式为ReferenceType :: [TypeArguments]标识符,则调用方法的主体类似地具有用于编译时声明的方法调用表达式的效果,该编译时声明是方法引用表达式的编译时声明。方法调用表达式的运行时评估如§15.12.4.3,§15.12.4.4和§15.12.4.5所述,其中:

  • 调用方式是从§15.1.2.3中指定的编译时声明派生的。

  • 如果编译时声明是实例方法,则目标引用是调用方法的第一个形式参数。否则,没有目标引用。

  • 如果编译时声明是实例方法,则方法调用表达式的参数(如果有)是调用方法的第二个和后续形式参数。否则,方法调用表达式的参数是调用方法的形式参数。

有趣的部分被我加粗了。

答案 1 :(得分:3)

下面的MyComparator实现了Comparator。它有两个参数。
与lambda表达式(d1,d2) -> d1.compareTo(d2)
相同 并与方法引用Double::compareTo

相同

方法引用是相同的,因为d1Double,因此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);
   }
}

答案 2 :(得分:-1)

u可以使用这两种方法之一来比较Double

listOfDouble.stream().max(Double::compareTo);
listOfDouble.stream().max(Comparator.naturalOrder());
相关问题