7

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

它说:

Java API 在 java.util.function 包中定义了几个通用功能接口。其中一个接口 BiFunction 描述了具有参数类型 T 和 U 以及返回类型 R 的函数。您可以将我们的字符串比较 lambda 保存在该类型的变量中:

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

但是,这并不能帮助您进行排序。没有需要 BiFunction 的 Arrays.sort 方法。如果您以前使用过函数式编程语言,您可能会觉得这很奇怪。但是对于 Java 程序员来说,这很自然。诸如 Comparator 之类的接口具有特定用途,而不仅仅是具有给定参数和返回类型的方法。Java 8 保留了这种风格。当您想使用 lambda 表达式做某事时,您仍然希望牢记表达式的用途,并为其提供特定的功能接口。

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

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

那么,文章中的信息是不正确的,还是我在这里误读了什么?

谢谢!

4

3 回答 3

22

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

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

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

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

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

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

Arrays.sort(array, bifunc::apply);  
于 2015-02-05T07:25:56.887 回答
3

这篇文章在某种意义上是正确的,你不能根据BiFunction类型的对象进行排序,但你总是可以使用Comparator. 但是,嘿,他们都可以拥有相同的身体。例如:

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. 但是您仍然无法传递funcsort. java8 中的 Lambda 是一些FunctionalInterface的实现。功能接口根据其引用类型获取其类型。这就是初始化时相同的 lambda 可以是 aBiFunctionComparator.

但是一旦构造了一个 lambda 并且它得到了它的类型,那么你就不能改变它了。因此,您不能将func类型传递BiFunction给期望的排序Comparator

于 2015-02-05T05:55:52.043 回答
2

文章是正确的。您不能将例如 a 分配BiFunction给 a Comparator

话虽如此,Brian Goetz 写的这篇很棒的文章很好地解释了这个问题。

当编译器遇到 lambda 表达式时,它首先将 lambda 主体降低(脱糖)为参数列表和返回类型与 lambda 表达式匹配的方法

因此,可以对 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$1 as Consumer] );
    }

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

所以,在 and 的情况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 表达式匹配

于 2015-02-05T08:02:57.763 回答