使用方法引用vs lambdas时,堆栈跟踪是否更少可导航?

时间:2015-11-13 11:45:57

标签: java lambda java-8 stack-trace method-reference

我刚刚在Eclipse中进行了快速实验。

public class StackTractTest {

  static class Nasty {
    public Integer toInt() {
      if (1 == 1) throw new RuntimeException();
      return 1;
    }
  }

  @Test
  public void methodReference() {
    Stream.of(new Nasty())
      .map(Nasty::toInt)
      .findFirst();
  }

  @Test
  public void lambda() {
    Stream.of(new Nasty())
      .map(n -> n.toInt())
      .findFirst();
  }

}

当方法参考测试失败时,跟踪开始

java.lang.RuntimeException
    at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11)
    at com.example.StackTractTest$$Lambda$1/1681433494.apply(Unknown Source)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)

虽然跟踪的末尾(未显示)确实链接回findFirst上的行,但没有对使用方法引用的行的引用。

lamdba stacktrace开始时

java.lang.RuntimeException
    at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11)
    at com.example.StackTractTest.lambda$0(StackTractTest.java:26)
    at com.example.StackTractTest$$Lambda$1/1681433494.apply(Unknown Source)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)

正确识别lambda用于第26行。

这是Eclipse编译器的特性还是这是使用方法引用的一般缺点,在选择它们和lambda时应该考虑这些引用?

2 个答案:

答案 0 :(得分:4)

不,这就是目前的实施方式。

引用Brian Goetz撰写的关于lambda表达式翻译的a paper

  

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

     

...

     

方法引用的处理方式与lambda表达式相同,不同之处在于大多数方法引用不需要被置于新方法中;我们可以简单地为引用的方法加载一个常量方法句柄,并将其传递给metafactory。

两个堆栈跟踪之间的唯一区别是具有显式lambda的那个已经添加了这一行:

at com.example.StackTractTest.lambda$0(StackTractTest.java:26)

这是因为lambda由javac翻译成新生成的方法,你实际上可以在stacktrace中看到这个新方法是lambda$0

使用方法引用,不必生成新方法,因为它直接引用现有方法。

答案 1 :(得分:2)

不 - 实际上你会更清晰。

lambda版本中出现at com.example.StackTractTest.lambda$0(StackTractTest.java:26)行的事实提醒您,对于此技术,已创建,而使用方法引用时不会创建任何额外的内容。

lambda是在运行时创建的,方法引用可以在编译时构造。