【编者的话】2014年3月份众人期待已久的Java 8发布了,新版本从语言、编译器、类库和工具等方面对Java进行了诸多改进与提升,一时间风光无限;而JVM体系的另一门语言Scala则因为融合了函数式编程语言与面向对象编程语言的优点,从诞生以来就一直备受瞩目,迅速赢得了社区的强烈支持。两门语言孰优孰劣或许不能简单地做出定论,这取决于具体的应用场景、资源约束以及团队偏好等因素,但是无论作何选择首先都需要对它们有深入的了解,本文来自于Zappos公司Hussachai Puripunpinyo在Dzone上发表的一篇文章,介绍了他自己对Java和Scala Lambda表达式的看法。

\\

Hussachai Puripunpinyo认为Java是一门静态的强类型语言,因此虽然在Java 8 中函数已经成了一等公民,可以作为函数的参数或者返回值来传递,但是它必须要有一个类型,那就是接口,而Lambda表达式就是实现了Functional接口的对象。虽然开发人员不需要为函数对象的创建而担心,因为编译器会做这些事情,但是Java并没有Scala那么出色的类型推理机制,在Java中声明Lambda表达式必须要指定目标类型。考虑到Java必须维持向后兼容性,这样做也是可以让人接受和理解的,事实上在兼容性方面Java已经做的足够好了,例如Thread.stop()在JDK 1.0中就已经有了,虽然被标记为“已废弃”数十年,但是现在依然存在,因而不应该因为其他语言有更好的语法就期望Java快速地改变自己的语法。

\\

为了支持Lambda表达式Java引入了函数式接口,该接口只有一个抽象方法。@FunctionalInterface是一个注解,用来表明被注解的接口是一个函数式接口,该注解是可选的,只有需要对接口是否符合契约做检查的时候才需要使用。

\\

在Java中,Lambda表达式必须要有一个类型,而且类型必须有且仅有一个抽象方法,而大部分已有的回调接口已经满足这一需求,因此用户不需要对它们做出任何改变就能够重用这些接口。例如:

\\

\//在Java 8之前\Runnable r = new Runnable(){  \  public void run(){    \    System.out.println(“This should be run in another thread”);  \  }\};\//Java 8\Runnable r = () -\u0026gt; System.out.println(“This should be run in another thread”);\

\\

对于有一个参数并且有返回值的函数,Java 8提供了一组通用的函数式接口,这些接口在java.util.function包中,使用方式如下:

\\

\//Java 8\Function parseInt = (String s) -\u0026gt; Integer.parseInt(s);\

\\

因为参数类型可以从Function对象的类型声明中推断出来,所以类型和小括号都可以省略:

\\

\//Java 8\Function parseInt = s -\u0026gt; Integer.parseInt(s);\

\\

对于需要两个参数的函数,Java 8提供了BiFunction:

\\

\//Java 8\BiFunction multiplier = \  (i1, i2) -\u0026gt; i1 * i2; //you can’t omit parenthesis here!\

\\

对于需要3个及以上参数的接口,Java 8并没有提供相应的TriFunction、QuadFunction等定义,但是用户可以定义自己的TriFunction,如下:

\\

\//Java 8\@FunctionalInterface\interface TriFunction {  \  public R apply(A a, B b, C c);\}\

\\

在引入了之前定义好的接口之后就可以这样声明Lambda表达式:

\\

\//Java 8\TriFunction sumOfThree \  = (i1, i2, i3) -\u0026gt; i1 + i2 + i3;\

\\

对于语言的设计者为什么会止步于BiFunction,Hussachai Puripunpinyo认为TriFunction、QuadFunction等需要更多参数的接口需要太多的类型声明,接口的定义变得非常长,同时又怎么决定定义到哪一个才最合适呢,总不能一直定义到包含9个参数和一个返回值类型的EnnFunction吧!

\\

以上示例显示参数越多,类型定义越冗长,甚至可能整整一行都是类型声明,那么必须要声明类型么?答案是在Java中必须如此,但是在Scala中就简单的多了。

\\

Scala也是一门静态强类型的语言,但是它从诞生开始就是一门函数式语言,完美融合了面向对象范式和函数式语言范式。Scala中的Lambda表达式也有一个类型,但是语言的设计者采用了数字而不是拉丁语来命名,Scala为开发者提供了0到22个参数的接口定义(Function0、Function1、… Function22),如果需要更多的参数,那么或许是开发者在设计上就存在问题。在Scala中Function的类型是特性(trait),类似于Java中的抽象类。

\\

Scala中的Runnable示例与Java中的实现方式不同:

\\

\//Scala\Future(println{“This should be run in another thread”})\//以上代码等同于\//Java 8\//assume that you have instantiated ExecutorService beforehand.\Runnable r = () -\u0026gt; System.out.println(“This should be run in another thread”);\executorService.submit(r);\

\\

在Scala中声明一个Lambda表达式不必像Java那样必须显式指定类型,而且方式也有很多:

\\

\//Java 8\Function parseInt = s -\u0026gt; Integer.parseInt(s);\\//Scala\val parseInt = (s: String) =\u0026gt; s.toInt\//or\val parseInt:String =\u0026gt; Int = s =\u0026gt; s.toInt\//or\val parseInt:Function1[String, Int] = s =\u0026gt; s.toInt\\

\\

如果需要更多的参数:

\\

\//Java 8\PentFunction sumOfFive \  = (i1, i2, i3, i4, i5) -\u0026gt; i1 + i2 + i3 + i4 + i5;\\//Scala\val sumOfFive = (i1: Int, i2: Int, i3: Int, i4: Int, i5: Int) =\u0026gt; \  i1 + i2 + i3 + i4 + i5;\

\\

可以看到,Scala的语法更简洁,可读性更好,开发者不需要声明接口类型,通过参数列表中的类型就能看出对象的类型。

\\

\//Java 8\PentFunction \  sumOfFive = (i1, i2, i3, i4, i5) -\u0026gt; i1 + i2 + i3 + i4 + i5;\\//Scala\val sumOfFive = (i1: String, i2: Int, i3: Double, i4: Boolean, i5: String) \=\u0026gt; i1 + i2 + i3 + i4 + i5;\

\\

对于上面这段代码,开发者一打眼就能看出i3是Double类型的,但是在Java 8中开发者必须要数一数才能看出来,如果要在Java 8中达到这种效果,那只有从格式上来做文章了:

\\

\//Java 8 \PentFunction sumOfFive \= (Integer i1, String i2, Integer i3, Double i4, Boolean i5) \-\u0026gt; i1 + i2 + i3 + i4 + i5;\

\\

但是这真是非常糟糕,开发者必须一次次地键入类型,另外,Java 8并没有定义PentFunction,你还必须自己定义:

\\

\//Java 8\@FunctionalInterface\interface PentFunction {  \  public R apply(A a, B b, C c, D d, E e);\}\

\\

Hussachai Puripunpinyo认为Scala在函数式方面做的更好,一方面是因为Scala本身就是一门函数式语言,另一方面是因为Java语言的设计者在引入新东西的时候必须要考虑兼容性,因而有很多约束。但是即使如此,Java 8依然引入了一些非常酷的特性,例如方法引用,该特性就能够让Lambda表达式的声明更加简短:

\\

\//Java 8\Function parseInt = s -\u0026gt; Integer.parseInt(s);\//使用方法引用可以简写为:\//Java 8\Function parseInt = Integer::parseInt;\

\\

在Java 8中,方法引用的构建规则有3种:

\\

  1. (args) -\u0026gt; ClassName.staticMethod(args);\\
    可以重写为ClassName::staticMethod;\\
Function intToStr = String::valueOf;

\\ (instance, args) -\u0026gt; instance.instanceMethod(args);\\
可以重写为ClassName::instanceMethod;\\

BiFunction indexOf = String::indexOf;\

\\ (args) -\u0026gt; expression.instanceMethod(args);\\
可以重写为expression::instanceMethod;\\

\Function indexOf = new String()::indexOf;\

\

流API就大量使用了这种语法来简化代码的编写:

\\

\pets.stream().map(Pet::getName).collect(toList());\// The signature of map() function can be derived as\//  Stream map(Function super Pet, ? extends String\u0026gt; mapper)\

\\

编后语

\\

《他山之石》是InfoQ中文站新推出的一个专栏,精选来自国内外技术社区和个人博客上的技术文章,让更多的读者朋友受益,本栏目转载的内容都经过原作者授权。文章推荐可以发送邮件到editors@cn.infoq.com。

\\


感谢徐川对本文的审校。

\

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号:InfoQChina)关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入InfoQ读者交流群(已满),InfoQ读者交流群(#2))。

Java 8 vs. Scala之Lambda表达式相关推荐

  1. 【Java 8 in Action】Lambda表达式

    文章目录 Lambda表达式 Lambda表达式的介绍 Lambda表达式的语法 Method References Default methods Functional Interface 浅析La ...

  2. 不少Java程序员都觉得Lambda表达式很鸡肋,它到底有何用呢?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:https://urlify.cn/B3uiI3 # 什么是 ...

  3. java lambda表达式_恕我直言你可能真的不会java第1篇:lambda表达式会用了么?

    本文配套教学视频:B站观看地址 在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应 ...

  4. Java 8th 函数式编程:lambda 表达式

    Lambda 表达式是 java 8th 给我们带来的几个重量级新特性之一,借用 lambda 表达式可以让我们的程序设计更加简洁.最近新的项目摒弃了 6th 版本,全面基于 8th 进行开发,本文将 ...

  5. 【Java】函数式编程思想-Lambda表达式

    面向对象的思想:做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情. 函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程 Java 8(JDK 1.8 ...

  6. Java—一篇读懂java集合(Collection/Map)及Lambda表达式

    集合简介   在集合类之前,我们使用数组存储,数组既可以存储基本数据类型的值,也可以存储对象(对象的引用变量),但是集合只能存储对象.   Java集合类似于一种容器,将同类型的对象(实际为对象引用) ...

  7. java thread lambda_Java8新特性--Lambda表达式

    从java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能. 很长一段时间java被吐槽是冗余和缺乏函数式编程能力的语言,随着函数式编程的流行java8种也引入了 这 ...

  8. 【Java】Java8新特性Lambda表达式和Stream API

    Lambda表达式是实现支持函数式编程技术的基础. 函数式编程与面向对象编程:函数式编程将程序代码看作数学中的函数,函数本身作为另一个函数参数或返回值,即高阶函数.而面向对象编程按照真实世界客观事物的 ...

  9. 【java学习之路】(java SE篇)013.lambda表达式

    lambda表达式 Lambda表达式是 Java8 中最重要的新功能之一.使用 Lambda 表达式可以替代只有一个抽象函数的接口实现,告别匿名内部类,代码看起来更简洁易懂.Lambda表达式同时还 ...

最新文章

  1. 梯度下降优化算法概述
  2. pycharm如何设置注释的字体颜色
  3. nginx配置长连接
  4. 第一次正经面试之发现自己的缺陷和不足
  5. 文献记录(part79)--光学影像序列中基于多视角聚类的群组行为分析
  6. 什么是485转光纤?485光纤转换器功能特点及技术参数详解
  7. 设计模式:单例模式7种写法
  8. HDU 1712 ACboy needs your help(分组背包入门题)
  9. 阔别263天游戏版号回归:巨头无缘,投资机会从何凸显?
  10. 简单实现同一局域网下的本地网页访问
  11. 持久层框架常用关键字 NE GE LE GT LT EQ 等等
  12. java unhandled,Unhandled Exception thrown: class java.lang.ClassCastException
  13. PHP的strtolower()和strtoupper()函数在安装非中文系统的服务器下可能会将汉字转换为乱码
  14. 保障信息安全不违规,App应满足哪些法律规定
  15. Mac 解决 ERROR launching ‘JD-GUI‘
  16. MathType中文版公式编辑器操作激活教程
  17. EMR 上的 Spark 或 Hive 作业失败并出现 HTTP 503 “Slow Down” AmazonS3Exception
  18. 我这些年从来没有用过算法,除了出去面试的时候
  19. html 字体图标转换工具,字体转换器
  20. 高级计算机网络 外文文献,计算机网络新技术外文文献翻译

热门文章

  1. 直线宽度2 points wide_OpenGL 绘图实例二之直线和圆弧的绘制
  2. ES5和6的一些新特性
  3. 智能车竞赛技术报告 | 智能车视觉 - 中南林业科技大学 - 弃车人队
  4. 航天智慧物流创意组-技术培训二期
  5. 2020年春季学期信号与系统课程作业参考答案-第十二次作业
  6. c语言编一个dll 用message box 弹出一个对话框,Qt学习之路(17): Qt标准对话框之QMessageBox...
  7. otf和ctf的意义_光学信息技术原理及应用 OTF与CTF的比较与计算.ppt
  8. java删除本地文件_读取Properties文件六种方法
  9. 为什么python打开pygame秒关闭后在运行_当我关闭Pygame时屏幕冻结
  10. java arraylist 构造_Java基础五:构造方法、ArrayList