可以将BiFunction引用传递给期望功能接口的方法吗?

时间:2015-02-05 04:41:16

标签: java java-8 lambda bifunctor

我一直只使用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程序员来说,这很自然。一个界面如   比较器有一个特定的目的,而不仅仅是给定的方法   参数和返回类型。 Java 8保留了这种风格。当你想要的时候   要使用lambda表达式做一些事情,你仍然希望保留   记住表达的目的,并具有特定的功能   它的界面。

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

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

那么,文章中的信息是否不正确,或者我在这里读错了什么?

谢谢!

3 个答案:

答案 0 :(得分:20)

我没有看到链接的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);

{{1}}

答案 1 :(得分: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完全相同的lambda。但您仍然无法将func传递给sort。 java8中的Lambdas是一些FunctionalInterface的实现。功能接口根据其引用类型获取其类型。这就是初始化中相同的lambda可以是BiFunction还是Comparator

但是一旦lambda被构造并且它被输入,那么你就无法改变它。因此,您无法将类型func的{​​{1}}传递给期望BiFunction

的排序

答案 2 :(得分:2)

文章是正确的。你无法指定例如BiFunctionComparator

话虽如此,Brian Goetz写的great article以一种很好的方式解释了这个问题。

  

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

所以,一个lambda可以 desugared - 但是这意味着什么?好吧,基本上它意味着创建一个新方法(可能)以某种方式匹配lamdba。

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

上面的代码 desugared 就像这样:

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);
    }
}

因此,对于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表达式与匹配,也无法重新分配