Java8 Lambda表达式

 

一,java8为何会出现Lambda表达式

Lambda表达式能够理解为一种匿名函数:它没有名称,但有参数列表、函数主体、返回类型,可能还有一个能够抛出的异常的列表,能够简洁地传递代码。java

•匿名——咱们说匿名,是由于它不像普通的方法那样有一个明确的名称:写得少而想得多!
•函数——咱们说它是函数,是由于Lambda函数不像方法那样属于某个特定的类。但和方法同样,Lambda有参数列表、函数主体、返回类型,还可能有能够抛出的异常列表。
•传递——Lambda表达式能够做为参数传递给方法或存储在变量中。
•简洁——无需像匿名类那样写不少模板代码。

好比,利用Lambda表达式,能够更为简洁地自定义一个Comparator对象。程序员

// 使用匿名类,按照重量升序对库存排序
inventory.sort(new Comparator<Apple>() {
    public int compare(Apple a1, Apple a2) {
        return a1.getWeight().compareTo(a2.getWeight());
    }
});
System.out.println(inventory);
// 用Lambda表达式,按照重量升序对库存排序
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
System.out.println(inventory);

Lambda表达式有三个部分:express

•参数列表——这里它采用了Comparator中compare方法的参数,两个Apple。
•箭头——箭头->把参数列表与Lambda主体分隔开。
•Lambda主体——比较两个Apple的重量。表达式就是Lambda的返回值了。

为了进一步说明,下面给出了Java 8中五个有效的Lambda表达式的例子。ide

//Java 8中有效的Lambda表达式
//第一个Lambda表达式具备一个String类型的参数并返回一个int。Lambda没有return语句,由于已经隐含了return
(String s) -> s.length() 
//第二个Lambda表达式有一个Apple 类型的参数并返回一个boolean(苹果的重量是否超过150克)
(Apple a) -> a.getWeight() > 150 
//第三个Lambda表达式具备两个int类型的参数而没有返回值(void返回)。注意Lambda表达式能够包含多行语句,这里是两行
(int x, int y) -> {    
    System.out.println("Result:");
    System.out.println(x+y);
}
//第四个Lambda表达式没有参数,返回一个int
() -> 42 
//第五个Lambda表达式具备两个Apple类型的参数,返回一个int:比较两个Apple的重量
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())

 Java语言设计者选择这样的语法,是由于C#和Scala等语言中的相似功能广受欢迎。Lambda的基本语法是(parameters) -> expression或(请注意语句的花括号)(parameters) -> { statements; }函数

 

 

 

 

 二,Lambda使用限制

Lambda表达式能够被赋给一个变量,或传递给一个接受函数式接口做为参数的方法,这个Lambda表达式的签名要和函数式接口的抽象方法同样spa

可能会想:“为何只有在须要函数式接口的时候才能够传递Lambda呢?”语言的设计者也考虑过其余办法,例如给Java添加函数类型。可是他们选择了如今这种方式,由于这种方式天然且能避免语言变得更复杂。此外,大多数Java程序员都已经熟悉了具备一个抽象方法的接口的理念(例如事件处理)。 设计

 

附:只有一个抽象方法的接口为函数式接口,函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。咱们将这种抽象方法叫做函数描述符。例如,Runnable接口能够看做一个什么也不接受什么也不返回(void)的函数的签名,由于它只有一个叫做run的抽象方法,这个方法什么也不接受,什么也不返回(void)。3d

 

附: @FunctionalInterface又是怎么回事? 若是去看看新的Java API,会发现函数式接口带有@FunctionalInterface的标注。这个标注用于表示该接口会设计成一个函数式接口。若是用@FunctionalInterface定义了一个接口,而它却不是函数式接口的话,编译器将返回一个提示缘由的错误。例如,错误消息多是“Multiple nonoverriding abstract methods found in interface Foo”,代表存在多个抽象方法。请注意,@FunctionalInterface不是必需的,但对于为此设计的接口而言,使用它是比较好的作法。它就像是@Override标注表示方法被重写了。code

 

内置函数式接口

 

 

 

 

 

 

三,Lambda快捷写法-方法引用

方法引用让能够重复使用现有的方法定义,并像Lambda同样传递它们。在一些状况下,比起使用Lambda表达式,它们彷佛更易读,感受也更天然。下面就是咱们借助更新的Java 8API,用方法引用写的一个排序的例子:对象

先前: 

inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

以后(使用方法引用和java.util.Comparator.comparing):

 inventory.sort(comparing(Apple::getWeight)); 

方法引用能够被看做仅仅调用特定方法的Lambda的一种快捷写法。它的基本思想是,若是一个Lambda表明的只是“直接调用这个方法”,那最好仍是用名称来调用它,而不是去描述如何调用它。事实上,方法引用就是让根据已有的方法实现来建立Lambda表达式。可是,显式地指明方法的名称,的代码的可读性会更好。它是如何工做的呢?当须要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。

 

 能够把方法引用看做针对仅仅涉及单一方法的Lambda的语法糖,由于表达一样的事情时要写的代码更少了。 如何构建方法引用 方法引用主要有三类。

(1)指向静态方法的方法引用(例如Integer的parseInt方法,写做Integer::parseInt)。

(2)指向任意类型实例方法的方法引用(例如String的length方法,写做String::length)。

(3)指向现有对象的实例方法的方法引用(假设有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例方法getValue,那么就能够写expensiveTransaction::getValue)。

第二种和第三种方法引用可能乍看起来有点儿晕。相似于String::length的第二种方法引用的思想就是在引用一个对象的方法,而这个对象自己是Lambda的一个参数。例如,Lambda表达式(String s) -> s.toUppeCase()能够写做String::toUpperCase。但第三种方法引用指的是,在Lambda中调用一个已经存在的外部对象中的方法。例如,Lambda表达式()->expensiveTransaction.getValue()能够写做expensiveTransaction::getValue。

相关文章
相关标签/搜索