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. Codeforces Little Dima and Equation 数学题解

    B. Little Dima and Equation time limit per test 1 second memory limit per test 256 megabytes input s ...

  2. servlet,RMI,webservice之间的区别

    最近项目中有提供或者调用别的接口,在纠结中到底是用servlet还是用webservice,所以上网查看了下他们以及RMI之间的区别,方便加深了解. 首先比较下servlet和webservice下  ...

  3. [IMX6DL][Android4.4] 电池低电量告警提示【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/51789964 之前版本的电池电量低是通过发送 intent ACTION_BATTERY_L ...

  4. qemu-kvm磁盘读写的缓冲(cache)的五种模式

    qemu-kvm磁盘读写的缓冲(cache)模式一共有五种,分别是writethrough, wirteback, none, unsafe, directsync当你对VM读写磁盘的性能有不同的要求 ...

  5. js 弹出对话框的方法总结

    原文:http://www.cnblogs.com/xiaofengfeng/archive/2012/10/20/2732784.html <!DOCTYPE html PUBLIC &quo ...

  6. apktool工具下载地址

    apktool工具下载地址 http://ibotpeaches.github.io/Apktool/

  7. Gerrit+apache+H2数据库简单安装配置及建库流程

    Gerrit 是一个基于 Web 的代码评审和项目管理的工具,面向基于 Git 版本控制系统的项目.因此需要Apache.Mysql.GIT等相关软件的支持 系统配置: 新装的UBANTU LINUX ...

  8. WebLogic之eclipse安装WebLogic插件

    转自:https://blog.csdn.net/magi1201/article/details/38323775

  9. 代码中特殊的注释技术——TODO、FIXME和XXX的用处 (转载)

    转自:http://blog.csdn.net/reille/article/details/7161942 作者:reille 本博客网址:http://blog.csdn.net/reille/, ...

  10. strncasecmp与strcasecmp用法(转载)

    转自: http://blog.csdn.net/acb0y/article/details/5333334 strcasecmp strcasecmp(忽略大小写比较字符串)  相关函数 bcmp, ...