当前位置: 首页 > 知识库问答 >
问题:

双函数引用是否可以传递给需要函数接口的方法?

孔鸿宝
2023-03-14

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

上面写着:

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

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

但是,这并不能帮助您进行排序。没有Arrays.sort方法想要BiFunction。如果您以前使用过函数式编程语言,您可能会对此感到好奇。但对于Java程序员来说,这是非常自然的。像比较器这样的接口具有特定的目的,而不仅仅是具有给定参数和返回类型的方法。Java8保留了这种味道。当您想使用lambda表达式做某事时,您仍然希望牢记表达式的目的,并为其提供特定的函数接口。

但是,当我看到这个线程:如何将lambda分配给Java8中的变量?

对这个问题的回答建议你完全按照引用的段落所说的去做你不能做的事情。

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

谢谢

共有3个答案

澹台新知
2023-03-14

这篇文章是正确的。例如,不能将双功能分配给比较器。

尽管如此,BrianGoetz写的这篇伟大的文章以一种很好的方式解释了这个问题。

当编译器遇到lambda表达式时,它首先将lambda主体降低(desugars)为参数列表和返回类型与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);
    }
}

因此,在双功能和比较器的情况下。所提供的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分配给类型(双功能或比较器),则无法重新分配它,即使lambda表达式匹配。

郎俊雅
2023-03-14

这篇文章在某种意义上是正确的,即您不能基于双功能类型的对象进行排序,但您始终可以使用比较器进行排序。但是,嘿,他们可以有相同的身体。例如:

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传递给排序。java8中的lambda是一些功能接口的实现。功能接口根据其引用类型获取其类型。这就是初始化时相同的lambda可以是双功能或比较器的方式。

但一旦lambda被构造并获得了它的类型,那么您就无法更改它。因此,您不能将类型为双函数的func传递给需要比较器的排序

卞嘉许
2023-03-14

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

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

如果您将变量声明为BiFunction

函数类型遵循所有常规规则,这一事实允许以最小的扰动添加此新功能。

如果你想用一个双功能做一个比较器,你所要做的就是添加::像这样应用:

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

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

 类似资料:
  • 问题内容: 为了不重复我的自我,我想创建一个函数来处理一些命令。 一旦我尝试运行它,我得到以下错误: 我研究了的实现,并且看起来函数签名正是我提供的。 在内部a 应该与可变参数相同,但对于编译器来说似乎不一样。 有没有办法将可变参数传递给? 问题答案: 您用另一个扩展 从语言规范的传递参数…参数 如果最终参数可分配给切片类型,则在参数后跟时可以将其作为参数的值原样传递。在这种情况下,不会创建新的切

  • 问题内容: 我想做这样的事情: 但是我得到这个错误 对成员’init()’的不明确引用 我知道我可以写 但是我想知道是否还有另一种方式。 问题答案: 问题在于不存在 仅 具有参数的初始化程序。 __ 目前只存在: 尽管该参数具有默认值,但是编译器仅在初始化程序的调用位置为您“填充”该默认值。 获取对函数本身的引用时,不会部分应用默认参数值,编译器也不会为默认参数值的所有可能组合生成额外的重载。后者

  • 问题内容: 与在或中使用的方式类似: 问题答案: 是。 如果你不理会关键字参数,这很简单并且可以工作: 如你所见,Python将为你提供一个包含所有参数的元组。 对于关键字参数,你需要将其作为单独的实际参数接受,如的所示。

  • 问题内容: 我是android新手,非常习惯于网络开发。在javascript中,当您要执行异步任务时,可以将函数作为参数传递(回调): 我想知道我们是否可以对android进行相同的操作,将函数引用传递给方法,然后它将运行它。 有什么建议 ? 问题答案: 是的,回调的概念在Java中也非常存在。在Java中,您可以这样定义一个回调: 人们通常会在这样的内部嵌套这些侦听器定义: 回调的完整实现如下

  • 问题内容: 我很好奇Go中是否有可能。我有多种方法的类型。是否可以有一个函数,该函数需要一个方法参数,然后将其称为类型? 这是我想要的一个小例子: Go认为type 有一个称为的方法,而不是用传入的方法名称替换它。 问题答案: 是的,有可能。您有2(3)个选项: 规范:方法表达式 该表达式产生的功能与第一个参数等效,但具有一个显式接收器。它有签名。 在这里,方法接收器是显式的。您只需将方法名称(具

  • 是否有办法在静态编程语言和Android中捆绑函数引用,以便可以从其他片段调用函数?例如,我的片段工厂方法如下所示: 我希望能够将我的tryAgainFunction保存在包中,以便进一步检索。 非常感谢! 编辑 最后,最合适的解决方案是使用热键的答案,然后在onViewCreated中使用传递的函数初始化监听器。完整代码如下: 谢谢大家的帮助!