LetsCoding.cn

天地之间有杆秤,拿秤砣砸老百姓。

Java 8:Lambda表达式(一)

Java 8中,最重要的一个改变使得代码更快、更简洁,并向FP(函数式编程)打开了方便之门。下面我们来看看,它是如何做到的。

在上世纪九十年代,Java被设计成了OOP语言,在当时,OOP是软件开发中的标杆。远在OOP还没有出现的时候,已经产生了FP语言,例如Lisp和Scheme,但是它们的益处,并没有受到学术圈外的人重视。最近,FP的重要性被提升了,因为它非常适合并发编程和事件驱动编程。然而,这并不意味着OO不好,相反,好的策略应该是混用OOP和FP。就算你对并发编程不感兴趣,这也很有道理。例如,如果编程语言有一个方便写函数表达式的语法,集合类库就能拥有强大的API。

Java 8中最主要的增强,就是把FP的概念深度整合进OO。在本文中,我将会展示其基本语法以及,在不同的上下文中,如何使用它。关键点如下:

  • Lambda表达式,就是有参数的代码块。
  • 在任何时候,你想稍后执行一个代码块时,用Lambda表达式。
  • Lambda表达式可以被转型成函数式接口。
  • Lambda表达式可以从封闭作用域有效访问final的变量。
  • 方法和构造器的引用可在不调用它们的情况下引用它们。
  • 你现在可以把default和static方法的具体实现写在接口中。
  • 你必须手动解决不同接口中任何的default方法冲突。
  • 为什么需要Lambda表达式?

    Lambda表达式是一个代码块,你可以绕过它,因此它能在稍后执行,仅一次或多次。在介绍语法(甚至是奇怪的名称)之前,让我们后退一步,看看一直以来,你在Java中,类似的代码块会在什么地方用到。

    当你想在一个独立的线程中执行代码时,你把代码放到Runnable的run方法中,就像这样:

    1. class Worker implements Runnable {
    2.      public void run() {
    3.          for (int i = 0; i < 1000; i++)
    4.              doWork();
    5.      }
    6.      // …
    7. }

    然后,当你想执行这段代码时,你创建一个Worker实例,把它提交给线程池,或者简单的开始一个新线程:

    1. Worker w = new Worker();
    2. new Thread(w).start();

    这里的关键点在于,run方法中包含你想在独立线程中执行的代码。

    想想用自定义的Comparator排序。如果你想以长度,而不以默认的字典顺序对字符串排序,你可以传递一个Comparator对象给sort方法:

    1. class LengthComparator implements Comparator< String > {
    2.      public int compare(String first, String second) {
    3.          return Integer.compare(first.length(), second.length());
    4.      }
    5. }
    6.    
    7. Arrays.sort(strings, new LengthComparator());

    sort方法会持续调用compare方法,重排乱序的元素,直到数组排序完毕。你给sort方法传递一个比较元素的代码片段,这段代码被整合进其余的、你也许不想重新去实现的排序逻辑。注意:如果 x等于y,Integer.compare(x, y)返回0;x < y,返回负数;x > y,返回正数。这个static方法在Java 7中被加入。你千万不能计算x - y来比较它们的大小,那样符号相反的大操作数会导致计算溢出的。

    作为另外一个延后执行的例子,考虑一个按钮回调。你新建一个继承Listener接口的类,把回调动作放进其中,创建它的一个实例,最后把实例注册到按钮。这种场景司空见惯,以至于很多程序员都使用“匿名类的匿名实例”语法:

    1. button.setOnAction(new EventHandler< ActionEvent >() {
    2.     public void handle(ActionEvent event) {
    3.         System.out.println("Thanks for clicking!");
    4.     }
    5. });

    重要的是handle方法中的代码,任何时候按钮被点击,它就会被执行。

    因为Java 8把JavaFX作为Swing GUI工具包的继任者,我在例子里是使用JavaFX。这些细节并不重要,因为在所有的UI工具包中,不管是Swing,JavaFX,还是Android,都是你给按钮一些代码,在按钮被点击的时候执行。

    在上面的三个例子中,你看到了相同的方式。代码块被传递给某人:线程池,sort方法或按钮,它将在稍后被调用。

    到现在为止,在Java中传递代码块并不简单。你不能只是传递代码块,Java是一个OOP语言,因此你必须先创建一个属于某个类的实例,而这个类拥有我们需要传递的代码块。

    在其他语言中,是可能直接使用代码块的。在很长一段时间里,Java的设计者们反对增加这个特性,毕竟,Java的伟大力量在于简单性和一致性。如果一个语言,包含所有的能够产生少量更紧凑代码的特性,它就会变成不可维护的一团糟。经管如此,在其他语言中,它们并不仅仅是可以更简单的启动一个线程,或者注册一个按钮点击的处理程序;它们中的大量API都更加简单,更加一致,更加强大。在Java里,人们本应该能够写出类似的API,它们使用继承特定函数的类的实例,但是,这样的API,让人用起来并不愉快。

    一段时间以来,问题变成,并不是要不要在Java中添加FP,而是怎么去添加。在符合Java的设计出来之前,设计者们花了几年的时间来做试验。在本文下一部分,你将会看到,你是如何在Java 8中使用代码块的。

    Lambda表达式的语法

    再想想上面排序的例子。我们传递比较字符串长度的代码。我们计算:

    1. Integer.compare(first.length(), second.length())

    fisrt和second是什么?它们都是字符串!Java是强类型语言,我们也必须指明这一点:

    1. (String first, String second) -> Integer.compare(first.length(), second.length())

    你看到了你的第一个Lambda表达式。它只是简单的代码块和必须传给它的变量说明。

    它的名称Lambda是怎么来的呢?很多年前,还在计算机出现之前,逻辑学家Alonzo Church想要形式化数学函数,让它具有更有效的可计算性。(奇怪的事,人们知道有些函数的存在,却没有人知道怎么计算它们的值。)他用希腊字母lambda(λ)来表示函数参数。如果他懂得Jav API,他可能会这样写:

    1. λfirst.λsecond.Integer.compare(first.length(), second.length())

    那为什么是字母λ呢?是Church用完了其他所有的字母了吗?实际上,伟大的《数学原理》使用ˆ来表示自由变量,它激发了Church用一个大写的lambda(λ)表示参数的灵感。但是最终,他还是使用了小写版本。自此以后,一个拥有参数的表达式就被称为了“Lambda表达式”。

    本文译自:Lambda Expressions in Java 8

原创文章,转载请注明: 转载自LetsCoding.cn
本文链接地址: Java 8:Lambda表达式(一)

posted on 2014-05-11 12:06 Rolandz 阅读(1668) 评论(1)  编辑  收藏 所属分类: 编程实践

评论

# re: Java 8:Lambda表达式(一) 2014-06-01 19:13 手赚网-手机赚钱软件排行,手机赚钱平台,网络赚钱http://www.szapk.cn

手赚网-手机赚钱软件排行,手机赚钱平台,网络赚钱http://www.szapk.cn!!  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

留言簿(1)

随笔分类(12)

随笔档案(19)

积分与排名

最新评论

阅读排行榜

评论排行榜