博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么函数式编程在Java中很危险?
阅读量:5880 次
发布时间:2019-06-19

本文共 2019 字,大约阅读时间需要 6 分钟。

摘要:函数式编程这个不温不火的语言由来已久。有人说,这一年它会很火,尽管它很难,这也正是你需要学习的理由。那么,为什么函数式编程在Java中很危险呢?也许这个疑问普遍存在于很多程序员的脑中,作者Elliotte对此发表了一些见解,我们一起来看看他是怎么说的。

在我的日常工作中,我身边的开发者大多是毕业于CS编程顶级院校比如MIT、CMU以及Chicago,他们初次涉及的语言是Haskell、Scheme及Lisp。他们认为函数式编程是一种自然的、直观的、美丽的且高效的编程样式。但奇怪的是,我和我的同事并没有为Haskell、Scheme、Lisp、Clojure、Scala而编程,这个行业里的绝大部分人都会使用Python、 Ruby、Java或C#等编程,因为它们用起来比较顺手。但在Java中,函数式编程却是低效且危险的。

为什么函数式编程在Java中很危险呢?

每隔几个月,我都会在调试中发现问题,究其原因最终可追溯到滥用函数的想法以及编程算法,更重要的原因是这个虚拟机无法创建这种编程样式。

最近想出一个很好的例子并说明了原因。Clojure (一个真正的函数式编程)返回到25整数列表:

  1. (take 25 (squares-of (integers))) 

此代码运行和响应速度都很快,输出结果:

  1. (1 4 9 16 25 36 49 64 … 576 625) 

现在,假设我们想要在Java中重写,如果我们以Gosling的方式来编写Java,那么该代码是简单、快速且明显的:

  1. for (int i=1; i<=25; i++)  
  2. System.out.println(i*i);  

但是,现在假设我们让它变得多功能性,在特定的假设范围内重置上面的Clojure样式:

尝试运行吧,OK,从堆转储(Heap Dump)中恢复 ?

  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  
  2. at java.util.Arrays.copyOf(Arrays.java:2760)  
  3. at java.util.Arrays.copyOf(Arrays.java:2734)  
  4. at java.util.ArrayList.ensureCapacity(ArrayList.java:167)  
  5. at java.util.ArrayList.add(ArrayList.java:351)  
  6. at Take25.integers(Take25.java:30)  
  7. at Take25.main(Take25.java:9) 

当Java输出后,Clojure如何处理函数,使该函数可返回到每一个int?

Clojure如同所有真正的函数语言(与Java不同)具备懒散赋值特性。它(指clojure)不会计算不被使用的值。它可以远离这个,因为Clojure不像Java,它是真正函数式语言,可以假定变量不发生变异,使求值的顺序变得无关紧要。因此,Clojure可以执行优化,但是Java编译器却不能——这就是为什么函数式编程在Java中是危险的原因。因为,Java不是真正的函数式语言,JIT和javac无法像在一个真正的函数式语言中积极且有效地优化函数构造对象,比如返回无穷个列表的标准函数计算,都是Java程序的死穴。这也是为什么函数式编程在Java中危险的原因。

这里,也许你会反对我的观点,OK,你无须在Java中返回所有的整数列表(或者甚至是所有的ints);但是相信没人做到这一点。

我们来一起看看比较现实的做法。这里我再次使用递归来计算而不是循环:

  1. public class Squares {  
  2.  
  3. public static void main(String args[]) {  
  4. squareAndPrint(1, Integer.parseInt(args[0]));  
  5. }  
  6.  
  7. public static void squareAndPrint(int n, int max) {  
  8. System.out.println(n * n);  
  9. if (max > n) {  
  10. squareAndPrint(n + 1, max);  
  11. }  
  12. }  
  13.  

开始运行!

很抱歉,堆栈溢出。这就是为什么在XOM中我小心翼翼地使用循环,即使递归的地方十分清楚也不使用递归。否则,精心配置XML文档可能会造成XOM-using程序来转储核心。因此,避免在非函数式语言中进行大量递归,正如Java和C不仅仅是性能需求,也是安全方面的要求。

写在最后:

我不是说函数式编程不好,也不是说函数式编程低效,其实,我热爱函数式编程。就像我的同事认为函数式编程是自然、直观且美丽的编程风格,但当它作为一们语言比如为Haskell重新设计时,Java中函数语句的性能Bug绝对能要了你的命。

转载地址:http://jmdix.baihongyu.com/

你可能感兴趣的文章
angular分页插件tm.pagination 解决触发二次请求的问题
查看>>
day08-文件操作
查看>>
教学-45 对象的相等
查看>>
贪食蛇
查看>>
关于Spring 中的事务
查看>>
为什么现在都用面向对象开发,为什么现在都用分层开发结构?
查看>>
【离散数学】 SDUT OJ 偏序关系
查看>>
写给学弟学妹的产品入门建议(持续更新)
查看>>
view视图总结
查看>>
oracle11g 数据库导出报“ EXP-00003:
查看>>
201521123009 《Java程序设计》第11周学习总结
查看>>
可解释的机器学习
查看>>
Python3之多线程学习
查看>>
aspx页面@Page指令解析
查看>>
POJ 2002
查看>>
MVC和MTV结构分析
查看>>
(转)微信网页扫码登录的实现
查看>>
mariadb启动报错:[ERROR] Can't start server : Bind on unix socket: Permission denied
查看>>
nginx的信号量
查看>>
《携程的技术演进之路》读后感
查看>>