这篇文章是infoQ上面关于java 8 和 scala 特性比较的一部分,原文实在是太长了,,分段翻译,先贴出来一部分,翻译的很差,欢迎拍砖。。。原文地址
Java8 终于要支持Lambda表达式!自2009年以来Lambda表达式已经在Lambda项目中被支持。在那时候,Lambda表达式仍被称为Java闭包。在咱们进入一些代码示例之前,先来解释下为何Lambda表达式在Java程序员中广受欢迎。
一、为何使用Lambda表达式
Lambda表达式一般使用在图形用户界面(GUI)的开发中。通常来讲,GUI编程将程序行为和事件作链接。好比,当用户按下一个按钮(触发一个事件),你的程序就须要去执行某些行为,多是将一些数据储存到一个数据存储器中。在Swing中,可使用ActionListener来实现:
class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
//do something
}
}
class UIBuilder {
public UIBuilder() {
button.addActionListener(new ButtonHandler());
}
}
这个例子代表了 ButtonHandler 类做为一个回调替换的用法。在这里 ButtonHandler 类仅包含 ActionListener 接口定义的 actionPerformed 方法。咱们可使用匿名内部类来简化代码:
class UIBuilder {
public UIBuilder() {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
//do something
}
})
}
}
这样代码简洁多了。更仔细的去看代码时,就会发现咱们还建立一个只生成一个实例的类,而这个实例也仅仅持有一个独立的方法。这刚好是Lambda表达式所能解决的其中一类问题。
二、Lambda表达式代替函数
一个lambda表达式从字面上讲就是一个函数。它定义了一个函数的输入参数和函数体。Java 8 中的,lambda表达式语法还没有肯定,不过大体应该相似这个样子的:
(type parameter) -> function_body
一个具体的例子:
(String s1, String s2) -> s1.length() - s2.length();
这个lambda表达式用来计算两个字符串的长度差。还有一些扩展的语法,好比避免参数的类型定义(咱们立刻见看到例子)还有使用{和}来支持多行定义。
Collections.sort() 方法是lambda表达的理想例子。它容许咱们将字符串按照长度排序:
List<String> list = Array.asList("loooooong", "short", "tiny");
Collections.sort(list, (String s1, String s2) -> s1.length() - s2.length());
> "tiny", "short", "loooooong".
因此,不像如今java必需要求的向sort方法输入一个已经实现的Comparator(比较器)而是传送一个lambda表达式咱们就能够获得相同的结果。
三、Lambda表达式代替闭包
lambda表达式有许多有趣的特性。其中之一是,它们是闭包。一个闭包容许函数访问直接词法做用域以外的变量。
String outer = "java 8"
(String s1) -> s1.length() - outer.length()
在例子中,lambda表达式访问了字符串 outer 这个做用域以外定义的变量。对于内联闭包来讲这是很难作到的。
四、Lambda表达式也支持类型推论
类型推论是java 7 引入的但它一样适用于lambda表达式。简单来讲,类型推论意味着程序员能够在任意一个编译器可以自动推断出类型的地方省略类型定义。
若是类型推论可以应用到前面的排序lambda表达式上,那么它就能写成下面的样子:
List<String> list = Arrays.asList(...);
Collections.sort(list, (s1, s2) -> s1.length()-s2.length());
就像你所见到的同样,参数s1和s2的类型被省略了。由于编译器知道list是一个字符串集合,它知道被用来做为比较器的lambda表达式一定是相同的类型。所以,这个类型不须要显式地声明,即便你有这么作的自由。
类型推论的主要优点就是减小样板代码,若是编译器能够为咱们识别类型,为何咱们必须本身定义它们。
五、珍爱Lambda表达式,远离匿名内部类
咱们来体会下,为什么lambda表达式和类型推论有助于简化咱们前面所提到的回调例子:
class UIBuilder {
public UIBuilder() {
button.addActionListener(e -> //process ActionEvent e)
}
}
咱们下载直接传送一个lambda表达式进入 addActionListener 方法来代替前面定义的持有回调方法的类。除了减小模板代码和提升可读性之外,它使咱们直接表达咱们惟一感兴趣的事情:处理事件。
在咱们了解lambda表达式更多优点以前,先来看看在Scala中的lambda表达式副本。
六、Scala中的Lambda表达式
在函数式编程中,函数是基本的构造块。Scala融合了java中的面向对象编程和函数式编程。在Scala中,一个lambda表达式是种叫作“函数”或者“函数文本”。Scala中的函数属于一等公民。它们能够被分配给vals或者vars(最终变量或者非最终变量),它们能够做为其余函数的参数,也能够组合成新的函数。
在Scala中一个函数文本写成以下形式:
(argument) => //funtion body
举例来讲,前面提到的java 用来计算两个字符串长度差的 lambda 表达式,在Scala中写做以下:
(s1: String, s2 :String) => s1.length - s2.length
Scala中的函数文本也是闭包。它能够访问在直接词法做用域以外定义的变量。
val outer =10
val myFuncLiteral = (y: Int) => y * outer
val result = myFuncLiteral(2)
> 20
这个例子结果是20.
正如你所见,咱们将函数文本分配给了变量 myFuncLiteral。
java 8 的lambda表达式和Scala的函数文本在语法和语义上的类似性是十分明显的。从语义上讲它们是相同的,而语法上的惟一不一样就是箭头符号(java8 ->, scala =>)和咱们没有提到的简化符号。