欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java 8里面lambda的最佳实践(1)(2)

来源: javaer 分享于  点击 5164 次 点评:70

Lambda的性能

Java 8里面lambda的最佳实践

Oracle公司的性能工程师Sergey Kuksenko有一篇很好的性能比较的文档: JDK 8: Lambda Performance study, 详细而全面的比较了lambda表达式和匿名函数之间的性能差别。这里是视频。 16页讲到最差capture)也和inner class一样, non-capture好的情况是inner class的5倍。

lambda开发组也有一篇ppt, 其中也讲到了lambda的性能(包括capture和非capture的情况)。看起来lambda最差的情况性能内部类一样, 好的情况会更好。

Java 8 Lambdas - they are fast, very fast也有篇文章 (需要翻墙),表明lambda表达式也一样快。

Lambda的阴暗面

前面都是讲Lambda如何改变Java程序员的思维习惯,但Lambda确实也带来了困惑

JVM可以执行任何语言编写的代码,只要它们能编译成字节码,字节码自身是充分OO的,被设计成接近于Java语言,这意味着Java被编译成的字节码非常容易被重新组装。

但是如果不是Java语言,差距将越来越大,Scala源码和被编译成的字节码之间巨大差距是一个证明,编译器加入了大量合成类 方法和变量,以便让JVM按照语言自身特定语法和流程控制执行。

我们首先看看Java 6/7中的一个传统方法案例:

  1. // simple check against empty strings 
  2. public static int check(String s) { 
  3. if (s.equals("")) { 
  4. throw new IllegalArgumentException(); 
  5. return s.length(); 
  6.  
  7. //map names to lengths 
  8.  
  9. List lengths = new ArrayList(); 
  10.  
  11. for (String name : Arrays.asList(args)) { 
  12. lengths.add(check(name)); 
  13.  
  14. 如果一个空的字符串传入,这段代码将抛出错误,堆栈跟踪如下: 
  15. 1 
  16. 2 
  17.  
  18. at LmbdaMain.check(LmbdaMain.java:19
  19. at LmbdaMain.main(LmbdaMain.java:34

再看看Lambda的例子

  1. Stream lengths = names.stream().map(name -> check(name)); 
  2.  
  3. at LmbdaMain.check(LmbdaMain.java:19
  4. at LmbdaMain.lambda$0(LmbdaMain.java:37
  5. at LmbdaMain$$Lambda$1/821270929.apply(Unknown Source) 
  6. at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193
  7. at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948
  8. at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512
  9. at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502
  10. at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708
  11. at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234
  12. at java.util.stream.LongPipeline.reduce(LongPipeline.java:438
  13. at java.util.stream.LongPipeline.sum(LongPipeline.java:396
  14. at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526
  15. at LmbdaMain.main(LmbdaMain.java:39


这非常类似Scala,出错栈信息太长,我们为代码的精简付出力代价,更精确的代码意味着更复杂的调试。

但这并不影响我们喜欢Lambda!

总结

在Java世界里面,面向对象还是主流思想,对于习惯了面向对象编程的开发者来说,抽象的概念并不陌生。面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。现实世界中,数据和行为并存,程序也是如此,因此这两种编程方式我们都得学。

这种新的抽象方式还有其他好处。很多人不总是在编写性能优先的代码,对于这些人来说,函数式编程带来的好处尤为明显。程序员能编写出更容易阅读的代码——这种代码更多地表达了业务逻辑,而不是从机制上如何实现。易读的代码也易于维护、更可靠、更不容易出错。

在写回调函数和事件处理器时,程序员不必再纠缠于匿名内部类的冗繁和可读性,函数式编程让事件处理系统变得更加简单。能将函数方便地传递也让编写惰性代码变得容易,只有在真正需要的时候,才初始化变量的值。

总而言之,Java更趋于完美了。




相关栏目:

用户点评