为什么函数式编程在Java中很危险?
摘要:函数式编程这个不温不火的语言由来已久。有人说,这一年它会很火,尽管它很难,这也正是你需要学习的理由。那么,为什么函数式编程在Java中很危险呢?也许这个疑问普遍存在于很多程序员的脑中,作者Elliotte对此发表了一些见解,我们一起来看看他是怎么说的。
在我的日常工作中,我身边的开发者大多是毕业于CS编程顶级院校比如MIT、CMU以及Chicago,他们初次涉及的语言是Haskell、Scheme及Lisp。他们认为函数式编程是一种自然的、直观的、美丽的且高效的编程样式。但奇怪的是,我和我的同事并没有为Haskell、Scheme、Lisp、Clojure、Scala而编程,这个行业里的绝大部分人都会使用Python、 Ruby、Java或C#等编程,因为它们用起来比较顺手。但在Java中,函数式编程却是低效且危险的。
为什么函数式编程在Java中很危险呢?
每隔几个月,我都会在调试中发现问题,究其原因最终可追溯到滥用函数的想法以及编程算法,更重要的原因是这个虚拟机无法创建这种编程样式。
最近Bob Martin想出一个很好的例子并说明了原因。Clojure (一个真正的函数式编程)返回到25整数列表:
- (take 25 (squares-of (integers)))
此代码运行和响应速度都很快,输出结果:
- (1 4 9 16 25 36 49 64 … 576 625)
现在,假设我们想要在Java中重写,如果我们以Gosling的方式来编写Java,那么该代码是简单、快速且明显的:
- for (int i=1; i<=25; i++)
- System.out.println(i*i);
- }
但是,现在假设我们让它变得多功能性,在特定的假设范围内重置上面的Clojure样式:
尝试运行吧,OK,从堆转储(Heap Dump)中恢复 ?
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
- at java.util.Arrays.copyOf(Arrays.java:2760)
- at java.util.Arrays.copyOf(Arrays.java:2734)
- at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
- at java.util.ArrayList.add(ArrayList.java:351)
- at Take25.integers(Take25.java:30)
- 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);但是相信没人做到这一点。
我们来一起看看比较现实的做法。这里我再次使用递归来计算而不是循环:
- public class Squares {
- public static void main(String args[]) {
- squareAndPrint(1, Integer.parseInt(args[0]));
- }
- public static void squareAndPrint(int n, int max) {
- System.out.println(n * n);
- if (max > n) {
- squareAndPrint(n + 1, max);
- }
- }
- }
开始运行!
很抱歉,堆栈溢出。这就是为什么在XOM中我小心翼翼地使用循环,即使递归的地方十分清楚也不使用递归。否则,精心配置XML文档可能会造成XOM-using程序来转储核心。因此,避免在非函数式语言中进行大量递归,正如Java和C不仅仅是性能需求,也是安全方面的要求。
写在最后:
我不是说函数式编程不好,也不是说函数式编程低效,其实,我热爱函数式编程。就像我的同事认为函数式编程是自然、直观且美丽的编程风格,但当它作为一们语言比如为Haskell重新设计时,Java中函数语句的性能Bug绝对能要了你的命。
为什么函数式编程在Java中很危险?的更多相关文章
- java编程思想-java中的并发(二)
二.共享受限资源 有了并发就可以同时做多件事情了.但是,两个或多个线程彼此互相干涉的问题也就出现了.如果不防范这种冲突,就可能发生两个线程同时试图访问同一个银行账户,或向同一个打印机打印,改变同一个值 ...
- Java多线程编程(1)--Java中的线程
一.程序.进程和线程 程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...
- Java学习疑惑(8)----可视化编程, 对Java中事件驱动模型的理解
我们编写程序就是为了方便用户使用, 我觉得UI设计的核心就是简洁, 操作过于繁琐的程序让很大一部分用户敬而远之. 即使功能强大, 但是人们更愿意使用易于操作的软件. 近年流行起来的操作手势和逐渐趋于成 ...
- 【Java编程】Java中的大整数计算
在上一篇文章中,我们实现了c语言中的大整数的运算,并且用Miller-Rabin算法实现了对大素数的测试.本来我准备用Java代码实现大整数的运算,查了一下资料发现Java中java.math的Big ...
- Java并发编程:Java中的锁和线程同步机制
锁的基础知识 锁的类型 锁从宏观上分类,只分为两种:悲观锁与乐观锁. 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新 ...
- 【Socket编程】Java中网络相关API的应用
Java中网络相关API的应用 一.InetAddress类 InetAddress类用于标识网络上的硬件资源,表示互联网协议(IP)地址. InetAddress类没有构造方法,所以不能直接new出 ...
- 【Java编程】Java中的字符串匹配
在Java中,字符串的匹配可以使用下面两种方法: 1.使用正则表达式判断字符串匹配 2.使用Pattern类和Matcher类判断字符串匹配 正则表达式的字符串匹配: ...
- 【java编程】java中的移位运算符
java中有三种移位运算符 << : 左移运算符,num << 1,相当于num乘以2 >> : 右移运算符,num >& ...
- 【并发编程】Java中的原子操作
什么是原子操作 原子操作是指一个或者多个不可再分割的操作.这些操作的执行顺序不能被打乱,这些步骤也不可以被切割而只执行其中的一部分(不可中断性).举个列子: //就是一个原子操作 int i = 1; ...
随机推荐
- 由Qt4.x项目移植到Qt5.x需要注意的事项
The Transition from Qt 4.x to Qt 5 The transition from Qt 4.x to Qt 5 is not expected to be signific ...
- Linux学习:netstat命令
Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态等.对于开发来说,很多时候用于查看端口占用情况. 执行netstat命令,其输出结果可以分成两部分: 1)一是“Active ...
- nginx 配置日志
http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $r ...
- Python: 在Unicode和普通字符串之间转换
Unicode字符串可以用多种方式编码为普通字符串, 依照你所选择的编码(encoding): <!-- Inject Script Filtered --> Toggle line nu ...
- win32 api Windows窗口的创建
windows窗口的创建有以下几个步骤: 1.创建注册窗口类 2.创建窗口句柄 3.显示更新窗口 4.消息循环 1.创建注册窗口类 所谓创建窗口类就是定义一个WNDCLASS类对象,并将该对象进行初始 ...
- Visual c++例子,可不使用常规的对话框资源模板的情况下,动态创建对话框的方法
详细说明:Visual c++例子,可不使用常规的对话框资源模板的情况下,动态创建对话框的方法.该方法可以在运行时在内存中直接建立对话框资源,使用起来更为灵活.适用于多个开发项目共享有界面的公用程序模 ...
- jQuery报错:Uncaught ReferenceError: $ is not defined
在使用jQuery的时候,发现有如下报错: Uncaught ReferenceError: $ is not defined (anonymous function) 出现这个报错的原因: 1.j ...
- UI 响应者链
响应者链 概念: 每一个应用有一个响应者链,我们的视图结构是一个N叉树(一个视图可以有多个子视图,一个子视图同一时刻只有一个父视图),而每一个继承UIResponder的对象都可以在这个N叉树中扮演 ...
- 【jQuery】使用JQ来编写面板的淡入淡出效果
本文与上一篇的<[jQuery]使用JQ来编写最主要的淡入淡出效果>(点击打开链接)为姊妹篇. 但上一篇仅仅是对文本的基本控制,本篇则是对面板元素进行控制. 尽管功能上很类似,可是所用到的 ...
- iOS 之使用CAShapeLayer中的CAGradientLayer实现圆环的颜色渐变
本文转载自:http://blog.csdn.net/zhoutao198712/article/details/20864143 在 Github上看到一些进度条的功能,都是通过Core Graph ...