简说JAVA8引入函数式的问题
JAVA8中加入lambda演算是一个令人兴奋的新特性——虽然这个新特性来得太迟了,目前的主流开发语言中,JAVA似乎是最后一个支持函数式思维的语言。
虽然晚了点,但总比没有好——况且我认为它的实现还是可以的,至少比C++的实现好一点(C++编译器不能自动很好的处理闭包环境,却要求程序员在代码中指定要引入到lambda表达式中的变量(捕获列表)——C++的类型系统过于丰富,如果没有捕获列表,则编译器无法得知应该通过“值”捕获还是通过“引用”捕获,而JAVA的类型系统简单很多,没有这个问题)。
以前每当我从Scala中回到Java,就有一种莫名的痛苦——Scala的集合库专为函数式而设计,其抽象程度高于Java的集合库,使得常常Scala两三行代码可以搞定的事情,在Java中要十几行代码才行。
现在使用Java8几个月了(我从beta版的时候就在使用openjdk8了),回到公司再去使用老掉牙的jdk6,也是痛苦得要命——说jdk6老掉牙一点也不过份,从03年jdk5开始到jdk7发布之前,java的语法从来没有变过,而到现在公司使用的最新版本的jdk还是jdk6——虽然Jdk8目前所支持的函数式语法在简洁性上仍然远不Scala,但也算是突飞猛进了。
在jdk8正式版本发布之后,网上关于jdk8的文章开始多了起来,基本上是一片叫好声。我个人也是非常喜欢这些变化,但因为:一来已经有很多人说这些好处了,我没有必要再缀述;二来现在使用jdk8的多半是爱学习的朋友,对于好的地方自然会花时间去体会,也不需要太多的讲。
所以我在这儿多说一点java中可能对于函数式思维还没有准备好的东西,而对其优点,如果有很多人都提过的,我就不在这里说了,如果谈到得比较少的,我就稍微讲一两句,比如这一项就很少有人提到:
新增的Stream接口的非终止运算的实现都是惰性求值的,这个设计在整体上保证了集合运算的运行效率。
在大数据时代,并发能力会成为语言的核心竞争力,而函数式语言开发的并发程序的性能通常都好于命令式语言,这也是为什么java这样的快20年的语言也开始转变了思维的原因之一。
例如:Scala与Java同是运行在JVM上的语言,但Scala开发的Spark相对于Java开发的Hadoop性能有100倍的提高。
下图来自于apache spark项目网站(逻辑回归算法执行时间对比)
这样大的差距是让人难以相信的,但目前来看,这就是事实——同一个JVM,仅仅是语言上的差别就能在性能上有这样的差据么?
我认为Hadoop的性能不如Spark的原因并不是使用Java就写不出那么高性能的东西出来,而是在Java中有一些东西使其在开发高性能的并发程序上存在很大的阻力。
我并没有深入研究Hadoop和Spark的内部机制,所以只就语言本身说一下Java8目前尚存在的(可能的)弱点。
注:以下先用一两句简单列一下,日后再补充。
一、存在空。
null是在正常的java代码中很常见的关键字,但对于函数式的思维中,空是没有意义的。
一个对象为空,就意味着无法调用这个对象的任何方法,而在函数式的程序中,如果某函数无法匹配出一个对象,通常也意味着这个函数结束了。
如果产生空对象还会继续的函数,那通常也意味着这个空引用会被赋予新的对象。
jdk8中也可以看到为避免空而修改的集合框架的方法,如:
Map接口中增加了一个方法getOrDefault来试图规避get方法会返回空的问题;
Jdk8新增的Optional类也是为模拟函数式语言中的模式匹配而增加的——空是不可能进行模式匹配的。
二、存在可变状态。
一个对象,如果是可变的,那就意味着这个对象的并发性有问题。
但java中要使一个类型的对象不可能被改变,是一个很麻烦的事情(想象一下所有属性全部加一个final),而开发一个可变状态的对象却非常容易。
虽然写一个符合纯函数式要求的函数不一定必须使用不可变状态,但如果所有对象都是不可变状态的,则写出来的函数就一定符合函数式的标准。
可变对象通常意味着并发调用这个对象时会出现问题,所以就需要对这个对象的某个部分加锁来规避问题,而锁是使并发性变差的最直接的原因。
三、无尾递归优化。
在Scala和Erlang这样的函数式风格的语言中,尾递归优化已是很平常的概念,但JAVA程序员多数都没有听说过这个概念(因为Java中没有尾递归优化)——关于尾递归优化可以参考我的另一篇文章《对SNL语言的解释器实现尾递归优化》。
函数式风格中的不可变状态的对象对并发性有很大的影响,但对于写惯了命令式语言代码的程序员来说,会产生一个非常不习惯的效应——没有循环。
想像一下:一个语言中没有for也没有while,可能是一个灾难。但如果熟悉了函数式的风格,即便没有循环,我们也可以实现等价的功能。
四、过于考虑向上兼容。
java从jdk5到现在的jdk8,没有增加任何一个保留字,所有的新的语法变化完全体现在代码结构上,很多新思想用库来实现,这大大影响了新思想的使用及推广。
不过这一点和性能的关系不是太大(库设计好了,性能也不差),但也是有点关系的——很多函数式语言中,部分常用的数据结构是语言的语法级别的,而不是库级别的。
五、没有增加新的更先进的线程模型。
前一段时间看到一段对话,是采访Ruby的作者松本行弘的,大概是这么说的:
问:如果时光倒流,你会做什么改变(对Ruby)?
答:去掉线程,使用更先进的基于actor的线程模型。
先列以上几条,以后随着理解的加深,可能会有所增加、删减或修改。
以上几点对于普通的java程序来说,是很平常的,但对于开发并发的程序或应用函数式思维,会不同程度的形成障碍。
再引用我的另一篇文章《用纯函数式思维在Java8下写的一段奇葩程序》,大家可以从这里感受一下Java8的lambda表达式在稍微复杂一点的情况下的表现是多么奇(chou)葩(lou)。
简说JAVA8引入函数式的问题的更多相关文章
- 谈一谈Java8的函数式编程(二) --Java8中的流
流与集合 众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...
- [译]Java8的函数式接口
Java8引入了 java.util.function 包,他包含了函数式接口,具体的描述在以下api说明文档中: 函数式接口为lambda表达式和方法引用提供目标类型.每个函数式接口有一个单独的抽象 ...
- 简析JAVA8函数式接口
一,定义 "有且只有一个抽象方法的接口"----函数式接口的定义. @FunctionalInterface public interface Ifun{ void test(); ...
- 谈一谈Java8的函数式编程 (三) --几道关于流的练习题
为什么要有练习题? 所谓学而不思则罔,思而不学则殆,在系列第一篇就表明我认为写博客,既是分享,也是自己的巩固,我深信"纸上得来终觉浅,绝知此事要躬行"的道理,因此之后的几篇博 ...
- JAVA8之函数式接口
由于JDK8已经发布一段时间了,也开始逐渐稳定,未来使用JAVA语言开发的系统会逐渐升级到JDK8,因为为了以后工作需要,我们有必要了解JAVA8的一些新的特性.JAVA8相对JAVA7最重要的一个突 ...
- java8 lambda 函数式编程
package com.atguigu.java8; import java.util.ArrayList; import java.util.Comparator; import java.util ...
- java8的函数式接口
函数式接口 就是在java8里允许你为一个接口(只有一个实现的,声明为FunctionalInterface注解的)实现一个匿名的对象,大叔感觉它与.net平台的委托很类似,一个方法里允许你接收一个方 ...
- Java8自定义函数式编程接口和便捷的引用类的构造器及方法
什么是函数编程接口? 约束:抽象方法有且只有一个,即不能有多个抽象方法,在接口中覆写Object类中的public方法(如equal),不算是函数式接口的方法. 被@FunctionalInterfa ...
- Java8 Functional(函数式接口)
Functional 函数式(Functional)接口 只包含一个抽象方法的接口,称为函数式接口. 你可以通过 Lambda 表达式来创建该接口的对象.(若 Lambda 表达式抛出一个受检异常(即 ...
随机推荐
- GridView根据一列自动计算(转载)
<%@ Page Language="C#" %> <%@ Import Namespace="System.Xml" %> <! ...
- 深入研究java.lang.Object类
前言:Java的类库日益庞大.所包括的类和接口也不计其数.但当中有一些非常重要的类和接口,是Java类库中的核心部分.常见的有String.Object.Class.Collection.ClassL ...
- 通过fsharp 使用Enterprise Library Unity 3 - 三种拦截模式的探索
这篇就三种拦截模式进行一下探索. 特性总结 类型 特点 其它 InterfaceInterceptor Innstance 仅单接口 类内部函数互相引用无法引起拦截行为 TransparentPr ...
- Windows7 配置匿名Samba文件共享
1.环境 系统:Windows 7 SP1 IP:192.168.118.151 2.配置 计算机|管理|本地用户和组|用户|Guest-->去掉账户已禁用 cmd|gpedit.msc|本地计 ...
- 演练:使用属性自定义 DataGrid 控件
演练:使用属性自定义 DataGrid 控件 Silverlight 此主题尚未评级 - 评价此主题 Silverlight DataGrid 控件支持常用表格式设置选项,例如交替显示不同的行 ...
- Ubuntu SDL lib 安装
/******************************************************************** * Ubuntu SDL lib 安装 * 说明: * 今天 ...
- bzoj1861 [Zjoi2006]Book 书架——splay
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1861 发现自己想splay的时候总是纠结那个点权是什么,因为splay原本是二分查找树... ...
- 转载:百为STM32开发板教程之十二——NAND FLASH
http://bbs.21ic.com/icview-586200-1-1.html 百为STM32开发板教程之十二——NAND FLASH 参考资料:百为stm32开发板光盘V3\百为stm32开发 ...
- bzoj 3143 [Hnoi2013]游走【高斯消元+dp】
参考:http://blog.csdn.net/vmurder/article/details/44542575 和2337有点像 设点u的经过期望(还是概率啊我也分不清,以下都分不清)为\( x[u ...
- Luogu P1638 逛画展 【二分答案】
题目描述 博览馆正在展出由世上最佳的 M 位画家所画的图画. wangjy想到博览馆去看这几位大师的作品. 可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必须说明两个数字, a和b,代表他要看 ...