- 概述
- 背景
- 例子
- 使用Lambda表達(dá)式改進代碼
- 總結(jié)
概述
Lambda表達(dá)式是Java8的一個重要的新特性港华,它使用一個表達(dá)式來表示一個方法接口塘偎。它還改進了Collection庫航唆,新的并發(fā)特性也提升了在多核環(huán)境下的性能。
背景
匿名內(nèi)部類
首先還要先從匿名內(nèi)部類說起,如果一個類只出現(xiàn)一次,那么可以使用如下方式實現(xiàn):
JButton testButton = new JButton("Test Button");
testButton.addActionListener(new ActionListener(){
@Override public void actionPerformed(ActionEvent ae){
System.out.println("Click Detected by Anon Class");
}
});
上面這段代碼可讀性不是很好赶站,也不夠優(yōu)雅。
功能性接口
ActionListener接口
package java.awt.event;
import java.util.EventListener;
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent e);
}
像ActionListener只有一個方法的接口叫功能性接口吓揪,比如 Runnable 和 Comparator.
Lambda表達(dá)式語法
一個Lambda表達(dá)式由以下三部分組成:
Argument list | Arrow token | Body |
---|---|---|
(int x, int y) | -> | x+y |
body可以是一個表達(dá)式或者一個語句塊亲怠。如果是表達(dá)式的形式,就執(zhí)行body的代碼并返回柠辞;如果是代碼塊的形式团秽,執(zhí)行完之后會把控制權(quán)交給調(diào)用方。
代碼塊的形式:
(String s) -> { System.out.println(s); }
表達(dá)式的形式:
(int x, int y) -> x + y
() -> 42
例子
下面是Comparator的例子叭首,使用了內(nèi)部類和lambda表達(dá)式习勤。
public class Person {
private String givenName;
private String surName;
private int age;
private Gender gender;
private String eMail;
private String phone;
private String address;
/** getter , setter and other methods **/
}
List<Person> personList = Person.createShortList();
// Sort with Inner Class
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.getSurName().compareTo(p2.getSurName());
}
});
System.out.println("=== Sorted Asc SurName ===");
for(Person p:personList){
p.printName();
}
// Use Lambda instead
// Print Asc
System.out.println("=== Sorted Asc SurName ===");
Collections.sort(personList, (Person p1, Person p2) -> p1.getSurName().compareTo(p2.getSurName()));
for(Person p:personList){
p.printName();
}
// Print Desc
System.out.println("=== Sorted Desc SurName ===");
Collections.sort(personList, (p1, p2) -> p2.getSurName().compareTo(p1.getSurName()));
for(Person p:personList){
p.printName();
}
可以注意到第二個lambda表達(dá)式?jīng)]有聲明參數(shù)類型,lambda支持“target typing”焙格,從上下文推斷出參數(shù)類型图毕。這里因為Comparator定義的是泛型,編譯器可以推斷出這里的兩個參數(shù)類型是Person眷唉。
使用Lambda表達(dá)式改進代碼
理論上lambda應(yīng)該支持DRY(Don't repeat yourself)原則予颤,并且使代碼可讀性更好。
下面這個例子依舊使用上面的Person類冬阳。假設(shè)我們需要區(qū)分一個集合里的Person的身份:
- Drivers:age>=16
- Draftees: age>=18 && ages<=25的男性青年
- Pilots: age>=23 && ages<=65
下面這個類負(fù)責(zé)查找集合中的Driver蛤虐、Draftee和Pilot
public class RoboContactMethods {
public void callDrivers(List<Person> pl){
for(Person p:pl){
if (p.getAge() >= 16){
roboCall(p);
}
}
}
public void emailDraftees(List<Person> pl){
for(Person p:pl){
if (p.getAge() >= 18 && p.getAge() <= 25 && p.getGender() == Gender.MALE){
roboEmail(p);
}
}
}
public void mailPilots(List<Person> pl){
for(Person p:pl){
if (p.getAge() >= 23 && p.getAge() <= 65){
roboMail(p);
}
}
}
public void roboCall(Person p){
System.out.println("Calling " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getPhone());
}
public void roboEmail(Person p){
System.out.println("EMailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getEmail());
}
public void roboMail(Person p){
System.out.println("Mailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getAddress());
}
}
很明顯上面這個類不符合DRY原則,每個方法都使用了循環(huán)肝陪,代碼也不易維護驳庭。如果改變了查找的規(guī)則,那這段代碼的改動會很大。
重構(gòu)
Java SE 8提供了java.util.function包饲常,有很多標(biāo)準(zhǔn)的功能性接口蹲堂,比如Predicate:
public interface Predicate<T> {
public boolean test(T t);
}
下面是使用Predicate接口改進的RoboContactMethods類:
public class RoboContactLambda {
public void phoneContacts(List<Person> pl, Predicate<Person> pred){
for(Person p:pl){
if (pred.test(p)){
roboCall(p);
}
}
}
public void emailContacts(List<Person> pl, Predicate<Person> pred){
for(Person p:pl){
if (pred.test(p)){
roboEmail(p);
}
}
}
public void mailContacts(List<Person> pl, Predicate<Person> pred){
for(Person p:pl){
if (pred.test(p)){
roboMail(p);
}
}
}
public void roboCall(Person p){
System.out.println("Calling " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getPhone());
}
public void roboEmail(Person p){
System.out.println("EMailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getEmail());
}
public void roboMail(Person p){
System.out.println("Mailing " + p.getGivenName() + " " + p.getSurName() + " age " + p.getAge() + " at " + p.getAddress());
}
}
調(diào)用:
List<Person> pl = Person.createShortList();
RoboContactLambda robo = new RoboContactLambda();
// Predicates
Predicate<Person> allDrivers = p -> p.getAge() >= 16;
Predicate<Person> allDraftees = p -> p.getAge() >= 18 && p.getAge() <= 25 && p.getGender() == Gender.MALE;
Predicate<Person> allPilots = p -> p.getAge() >= 23 && p.getAge() <= 65;
總結(jié)
本文主要介紹了Java的匿名內(nèi)部類,使用lambda表達(dá)式代替匿名內(nèi)部類贝淤,lambda表達(dá)式的正確語法柒竞,以及function包中Predicate接口。