为什么Stream.max接受Integer.compare作为输入参数?

时间:2019-02-20 19:32:54

标签: java java-stream comparator method-reference

stream.max方法采用Comparator,但Integer.compare不实现Comparator接口。唯一的相似之处是它们共享compare()方法的相同方法签名。因此,对于成为比较器输入参数的先决条件有什么困惑?谢谢。

示例:

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

3 个答案:

答案 0 :(得分:2)

在这种情况下,Integer::compare等同于其lambda形式:

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

这种lambda形式在逻辑上也等同于其匿名类形式:

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

答案 1 :(得分:2)

Comparator interface是一个功能接口,因此可以使用其方法签名符合该功能接口的任何lambda表达式或方法引用。

compare方法将两个对象进行比较,然后返回int以进行排序。方法引用Integer::compare引用了Integer's compare method,并且该方法的签名匹配,因此编译器允许此方法引用解析为Comparator实例。

当作为参数传递给方法,分配给变量以及传递给转换运算符的参数时,允许使用

Lambda表达式和方法引用。在这里,您的方法引用将作为参数传递给方法,因此编译器将其视为合法代码。

答案 2 :(得分:1)

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 Run-Time Evaluation of Method References

  

如果格式为ReferenceType :: [TypeArguments]标识符,则调用方法的主体类似地具有编译时声明的方法调用表达式的效果,该编译时声明是方法引用表达式的编译时声明。 。   
...

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

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

  •   

描述方法引用的解析,验证和调用方式的详细信息太多了,因此这里不涉及它,因此遍历JLS的这一部分绝对是一个好主意:-)