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方法中,就像这样:
-
class Worker implements Runnable {
-
public void run() {
-
for (int i = 0; i < 1000; i++)
-
doWork();
-
}
-
// …
-
}
然后,当你想执行这段代码时,你创建一个Worker实例,把它提交给线程池,或者简单的开始一个新线程:
-
Worker w = new Worker();
-
new Thread(w).start();
这里的关键点在于,run方法中包含你想在独立线程中执行的代码。
想想用自定义的Comparator排序。如果你想以长度,而不以默认的字典顺序对字符串排序,你可以传递一个Comparator对象给sort方法:
-
class LengthComparator implements Comparator< String > {
-
public int compare(String first, String second) {
-
return Integer.compare(first.length(), second.length());
-
}
-
}
-
-
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接口的类,把回调动作放进其中,创建它的一个实例,最后把实例注册到按钮。这种场景司空见惯,以至于很多程序员都使用“匿名类的匿名实例”语法:
-
button.setOnAction(new EventHandler< ActionEvent