BiFunction 引用可以传递给需要功能接口的方法吗?

Can BiFunction references be passed to methods expecting a functional interface?

我一直只使用 Java 6,现在正赶上了解 Java 8 中的新功能。我在这里阅读了这篇文章: http://www.drdobbs.com/jvm/lambda-expressions-in-java-8/240166764?pgno=2

它说:

The Java API defines several generic functional interfaces in the java.util.function package. One of the interfaces, BiFunction, describes functions with parameter types T and U and return type R. You can save our string comparison lambda in a variable of that type:

BiFunction<String, String, Integer> comp 
    = (first, second) -> Integer.compare(first.length(), second.length()); 

However, that does not help you with sorting. There is no Arrays.sort method that wants a BiFunction. If you have used a functional programming language before, you may find this curious. But for Java programmers, it's pretty natural. An interface such as Comparator has a specific purpose, not just a method with given parameter and return types. Java 8 retains this flavor. When you want to do something with lambda expressions, you still want to keep the purpose of the expression in mind, and have a specific functional interface for it.

但是,当我看到这个帖子时: How do you assign a lambda to a variable in Java 8?

那里的问题的答案建议按照引用的段落所说的做你不能做的事情。

所以,是文章中的信息不正确,还是我看错了什么?

谢谢!

这篇文章在某种意义上是正确的,您不能根据 BiFunction 类型的 object 进行排序,但您始终可以使用 Comparator。但是,嘿,他们可以有相同的 body。例如:

private static void sort(Comparator<String> ls){
        Arrays.sort(someArray, ls);
}

Comparator<String> comp = (String f1, String f2) -> Integer.compare(f1.length(), f2.length());
sort(comp);

BiFunction<String, String, Integer> func = (String f1, String f2) -> Integer.compare(f1.length(), f2.length());
sort((String f1, String f2) -> Integer.compare(f1.length(), f2.length())); //line-4

sort(func) // compiler error

在第 4 行上方,您可以传递与 func 完全相同的 lambda。但是你仍然无法将 func 传递给 sort。 java8 中的 Lambda 是一些 FunctionalInterface 的实现。功能接口根据其引用类型获取其类型。这就是初始化时相同的 lambda 可以是 BiFunctionComparator.

的方式

但是一旦构建了 lambda 并确定了类型,就无法更改它。因此,您不能将 BiFunction 类型的 func 传递给需要 Comparator

的排序

我在链接的 SO 答案中没有看到任何与文章相矛盾的内容。

类型系统的常规规则适用于功能接口

如果将变量声明为 BiFunction<String,String,Integer> bifunc,将不允许将其传递给需要 Comparator<String> 的方法,因为 BiFunction<String,String,Integer> 不是 子类型Comparator<String>

函数类型遵循所有常用规则这一事实使得这个新功能能够以最小的扰动添加。

如果你想从 BiFunction 中得到一个 Comparator,你所要做的就是像这样添加 ::apply

BiFunction<String,String,Integer> bifunc = (a,b) -> 
                               Integer.compare(a.length(), b.length());

Arrays.sort(array, bifunc::apply);  

这篇文章是正确的。你不能分配例如一个 BiFunction 到一个 Comparator

话虽如此,Brian Goetz 撰写的这篇 great article 很好地解释了这个问题。

When the compiler encounters a lambda expression, it first lowers (desugars) the lambda body into a method whose argument list and return type match that of the lambda expression

所以,lambda 可以脱糖 - 但这是什么意思?好吧,基本上这意味着(可能)创建了一种以某种方式与 lamdba 相匹配的新方法。

class A {
    public void foo() {
        List<String> list = ...
        list.forEach( s -> { System.out.println(s); } );
    }
}

上面的代码将被脱糖成这样:

class A {
    public void foo() {
        List<String> list = ...
        list.forEach( [lambda for lambda as Consumer] );
    }

    static void lambda(String s) {
        System.out.println(s);
    }
}

因此,在 BiFunctionComparator 的情况下。提供的 lambda 可以分配给两者:

// Assign the lambda to a BiFunction
BiFunction<String, String, Integer> b1 =
        (first, second) -> Integer.compare(first.length(), second.length());

// Assign the lambda to a Comparator
Comparator<String> c1 =
        (first, second) -> Integer.compare(first.length(), second.length());

// But, once the lambda has been assigned to a type you can not reassign it
BiFunction<String, String, Integer> b2 = c1; // <-- Error

请注意,一旦将 lambda 分配给一个类型(BiFunctionComparator),就不能重新分配它,即使 lambda 表达式匹配.