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

Lambda表达式与方法引用

金令秋
2023-03-14

IntelliJ一直建议我用方法引用替换我的lambda表达式。

两者之间有什么客观差异吗?

共有3个答案

杜俊楚
2023-03-14

作为用户stuchl4n3k写在评论质疑可能会发生异常。

让我们考虑一些变量field是未初始化的字段,然后:

field = null;
runThisLater(()->field.method());
field = new SomeObject();

不会崩溃,而

field = null;
runThisLater(field::method);
field = new SomeObject();

java会崩溃。lang.NullPointerException:尝试调用虚拟方法“java”。lang.Class java。朗,反对。getClass(),在方法引用语句行,至少在Android上是这样。

今天IntelliJ指出"可能会改变语义学",同时建议进行这种重构。

这种情况发生在“引用”特定对象的实例方法时。为什么?让我们检查15.13.3的前两段。方法引用的运行时评估:

在运行时,方法引用表达式的求值与类实例创建表达式的求值类似,只要正常完成生成对对象的引用。方法引用表达式的计算不同于方法本身的调用。

首先,如果方法引用表达式以ExpressionName或Primary开头,则对该子表达式求值。如果子表达式的计算结果为null,则会引发NullPointerException,方法引用表达式会突然完成。如果子表达式突然完成,方法引用表达式也会因为同样的原因突然完成。

对于lambda表达式,我不确定,最终类型是在编译时从方法声明中派生的。这只是对实际情况的简化。但是让我们假设方法runThisLater已被声明为例如void runThisLater(SamType obj),其中SamType是一些函数接口,然后runThisLater(()-

runThisLater(new SamType() {  
    void doSomething() { 
        field.method();
    }
});

其他信息:

  • 15.27.4。Lambda表达式的运行时评估
  • Lambda表达式的翻译
  • Lambda的状态,版本3,其中提到了SAM。
  • Lambda状态,最终。

朱淮晨
2023-03-14

由多条语句组成的长lambda表达式可能会降低代码的可读性。在这种情况下,在方法中提取这些语句并引用它可能是更好的选择。

另一个原因可能是可重用性。而不是复制

叶俊郎
2023-03-14

让我从一些角度来解释为什么我们在语言中添加了这个特性,而我们显然不需要(所有方法引用都可以表示为lambdas)

请注意,没有正确的答案。任何说“始终html" target="_blank">html" target="_blank">使用方法引用而不是lambda”或“始终使用lambda而不是方法引用”的人都应该被忽略。

这个问题在精神上与“我应该在什么时候使用命名类和匿名类”非常相似?答案是一样的:当你发现它更具可读性时。当然有肯定是一种或肯定是另一种的情况,但中间有很多灰色,必须使用判断。

方法refs背后的理论很简单:名字很重要。如果一个方法有一个名称,那么通常(但不总是!)是通过名称来引用它,而不是通过一包命令式的代码来调用它更清晰易读。

关于性能或字符计数的争论大多是转移注意力的,你应该忽略它们。目标是编写清晰的代码。经常(但不总是!)方法参考在这个指标上获胜,所以我们将其作为一个选项,用于这些情况。

关于方法引用是澄清还是混淆意图的一个关键考虑因素是,从上下文来看,所表示的函数的形状是否明显。在某些情况下(例如,map(Person::getLastName)),从上下文中可以很清楚地看出,需要一个将一个事物映射到另一个事物的函数,在这种情况下,方法引用会发光。在其他情况下,使用方法ref需要读者想知道所描述的是什么样的函数;这是一个警告信号,表明lambda可能更具可读性,即使它更长。

最后,我们发现,大多数人一开始会避开方法引用,因为他们觉得自己比lambdas更新、更奇怪,所以最初觉得它们“不太可读”,但随着时间的推移,当他们习惯了语法时,通常会改变他们的行为,并尽可能地倾向于方法引用。因此,请注意,您自己的主观初始“不太可读”反应几乎肯定会导致某些方面的熟悉偏差,您应该给自己一个机会,在提出文体观点之前,让自己对两者都感到舒适。

 类似资料:
  • 问题内容: 假设我有一个通用接口: 和方法sort: 我可以调用此方法并将lambda表达式作为参数传递: 那会很好的。 但是现在,如果我将接口设为非泛型,并且将方法设为泛型: 然后像这样调用: 它不会编译。它在lambda表达式中显示错误: “目标方法是通用的” 好的,当我使用编译时,它显示以下错误: 从此错误消息看来,编译器似乎无法推断类型参数。是这样吗 如果是,那为什么会这样呢? 我尝试了各

  • 它不编译。它在lambda表达式中显示错误: “目标方法是泛型的” 好的,当我使用编译它时,它显示了以下错误:

  • 问题内容: 鉴于这种: 编译器 对每种方法 执行的操作有什么 区别? 如果有的话,内存使用或运行时间是否有所不同?(即使很小,问题也只是学术上的) 问题答案: 这是Brett Oken链接的Brian Goetz的文档 的摘录: 当编译器遇到lambda表达式时,它首先将lambda主体降低(降低)到方法中 其参数列表和返回类型与lambda表达式的参数匹配,并可能带有一些其他参数(用于从词法范围

  • 用Java 8 lambdas到处乱搞。为什么当我向接口添加另一个方法时,这会给我一个错误: 不使用第二个方法也能正常工作:“public int getID(String name)

  • 我试图学习在Java8中使用lambda表达式的方法引用,但遇到了一些我无法完全理解的东西。 使用lambda表达式(而不是创建接口等),是否有更干净的方法来完成此操作?

  • (译注:目前支持lambda的gcc编译器版本为4.5,其它详细的编译器对于C++11新特性的支持请参考http://wiki.apache.org/stdcxx/C%2B%2B0xCompilerSupport) Lambda表达式是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数(译注:Lambda表达式也可以称为匿名函数,具有复杂行为的函数可以采用命名函数对象,当然,何谓复杂