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引入函数式的问题的更多相关文章

  1. 谈一谈Java8的函数式编程(二) --Java8中的流

    流与集合    众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...

  2. [译]Java8的函数式接口

    Java8引入了 java.util.function 包,他包含了函数式接口,具体的描述在以下api说明文档中: 函数式接口为lambda表达式和方法引用提供目标类型.每个函数式接口有一个单独的抽象 ...

  3. 简析JAVA8函数式接口

    一,定义 "有且只有一个抽象方法的接口"----函数式接口的定义. @FunctionalInterface public interface Ifun{ void test(); ...

  4. 谈一谈Java8的函数式编程 (三) --几道关于流的练习题

    为什么要有练习题?    所谓学而不思则罔,思而不学则殆,在系列第一篇就表明我认为写博客,既是分享,也是自己的巩固,我深信"纸上得来终觉浅,绝知此事要躬行"的道理,因此之后的几篇博 ...

  5. JAVA8之函数式接口

    由于JDK8已经发布一段时间了,也开始逐渐稳定,未来使用JAVA语言开发的系统会逐渐升级到JDK8,因为为了以后工作需要,我们有必要了解JAVA8的一些新的特性.JAVA8相对JAVA7最重要的一个突 ...

  6. java8 lambda 函数式编程

    package com.atguigu.java8; import java.util.ArrayList; import java.util.Comparator; import java.util ...

  7. java8的函数式接口

    函数式接口 就是在java8里允许你为一个接口(只有一个实现的,声明为FunctionalInterface注解的)实现一个匿名的对象,大叔感觉它与.net平台的委托很类似,一个方法里允许你接收一个方 ...

  8. Java8自定义函数式编程接口和便捷的引用类的构造器及方法

    什么是函数编程接口? 约束:抽象方法有且只有一个,即不能有多个抽象方法,在接口中覆写Object类中的public方法(如equal),不算是函数式接口的方法. 被@FunctionalInterfa ...

  9. Java8 Functional(函数式接口)

    Functional 函数式(Functional)接口 只包含一个抽象方法的接口,称为函数式接口. 你可以通过 Lambda 表达式来创建该接口的对象.(若 Lambda 表达式抛出一个受检异常(即 ...

随机推荐

  1. 大话设计模式C++实现-第14章-观察者模式

    一.UML图 关键词:Subject维护一个Observer列表.Subject运行Notify()时就运行列表中的每一个Observer的Update(). 二.概念 观察者模式:定义了一种一对多的 ...

  2. Redhat Linux 下安装Oracle 11g R2

    能够下载:http://download.csdn.net/detail/ykh554541184/8086647文档方便查阅 官方文档:http://docs.oracle.com/cd/E1188 ...

  3. debian webmin 安装

    /******************************************************************** * debian webmin 安装 * 说明: * 在服务 ...

  4. gdb core调试

    原文链接 http://blog.163.com/lanka83/blog/static/32637615200801793020182/http://blog.csdn.net/taina2008/ ...

  5. vue 练习 bug

    在使用vue slot分发内容时,如果要绑定事件,不能绑定在slot元素上,同样的不能绑定在自定义元素的模板上,只能绑定在html 元素上,才会生效 demo <my-component v-o ...

  6. ie7 总结

    1 ie7 对部分属性选择器严重区分大小写 在HTML中,属性名,例如id, title之类是不区分大小写的,CSS中的选择器也应该是如此.但是IE7对属性名是严格区分大小写的! 2 关于属性选择器, ...

  7. Python sklearn Adaboost

    1. Adaboost类库概述 scikit-learn中Adaboost类库比较直接,就是AdaBoostClassifier和AdaBoostRegressor两个,从名字就可以看出AdaBoos ...

  8. ASP.NET项目开发实战<<一键创建解决方案>>

    视频演示地址:http://www.youku.com/playlist_show/id_23192838.html 第一步:创建项目需要的数据库 打开辅助开发工具,如下图 从左侧菜单找到 项目数据库 ...

  9. Ruby 动态生成变量

    创建: 2018/03/21 更新: 2018/03/22 把标题ruby首字母大写 方法一: eval将字符串作为代码执行, 故写在里边 eval("@#{view_name.to_s} ...

  10. [Swift通天遁地]一、超级工具-(1)动态标签:给UILabel文字中的Flag和url添加点击事件

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...