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