Lambda表達式
JDK1.8的新特性之一
函數式編程思想
在數學中,函數就是有輸入量、輸出量的一套計算方案,也就是“拿什麼東西做什麼事情”。相對而言,面向對象過分強調“必須通過對象的形式來做事情”,而函數式思想則儘量忽略面向對象的複雜語法——強調做什麼,而不是以什麼形式做。
我們真的希望創建一個匿名內部類對象嗎?不。我們只是爲了做這件事情而不得不創建一個對象。我們真正希望做的事情是:將 run 方法體內的代碼傳遞給 Thread 類知曉。
傳遞一段代碼——這纔是我們真正的目的。而創建對象只是受限於面向對象語法而不得不採取的一種手段方式。
那,有沒有更加簡單的辦法?如果我們將關注點從“怎麼做”迴歸到“做什麼”的本質上,就會發現只要能夠更好地達到目的,過程與形式其實並不重要
Lambda引入
首先我們先看一個傳統的匿名內部類方式創建線程
public class ThreadDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是一個線程!");
}
}).start();
}
}
對於 Runnable 的匿名內部類用法,可以分析出幾點內容:
1.Thread 類需要 Runnable 接口作爲參數,其中的抽象 run 方法是用來指定線程任務內容的核心;
2.爲了指定 run 的方法體,不得不需要 Runnable 接口的實現類;
3.爲了省去定義一個 RunnableImpl 實現類的麻煩,不得不使用匿名內部類;
4.必須覆蓋重寫抽象 run 方法,所以方法名稱、方法參數、方法返回值不得不再寫一遍,且不能寫錯;
5.而實際上,似乎只有方法體纔是關鍵所在。
Lambda表達式格式:
Lambda省去面向對象的條條框框,格式由3個部分組成:
一些參數
一個箭頭
一段代碼
Lambda表達式的標準格式爲:(參數類型 參數名稱) -> { 代碼語句 }
格式說明:
小括號內的語法與傳統方法參數列表一致:無參數則留空;多個參數則用逗號分隔。
-> 是新引入的語法格式,代表指向動作。
大括號內的語法與傳統方法體要求基本一致。
Lambda表達式寫法:
public class ThreadDemo {
public static void main(String[] args) {
//匿名內部類創建線程方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是一個線程!");
}
}).start();
System.out.println("=============Lambda表達式=============");
//Lambda表達式方式
new Thread(()-> {
System.out.println("我是一個線程!");
}).start();
}
}
可以看到簡化了較多的代碼 ,其實根據Lambda表達式的簡化規則,我們還可以對代碼進行更深層次的簡化。
public class ThreadDemo {
public static void main(String[] args) {
//匿名內部類創建線程方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是一個線程!");
}
}).start();
System.out.println("=============Lambda表達式=============");
//Lambda表達式方式
new Thread(()-> {
System.out.println("我是一個線程!");
}).start();
System.out.println("=============Lambda表達式最終簡化=============");
//Lambda表達式進一步簡化
new Thread(()-> System.out.println("我是一個線程!")).start();
}
}
結果:
我是一個線程!
=============Lambda表達式=============
我是一個線程!
=============Lambda表達式最終簡化=============
我是一個線程!
我們可以看到最終的結果是一致的,證明我們使用的Lambda表達式是正確的。
Lambda表達式使用前提
- 使用Lambda必須要有接口作爲參數傳遞,並且要求接口中有且僅有一個抽象方法。
Lambda表達式簡化規則
- 參數類型可以省略。
- 如果參數僅有一個,小括號可以省略
- 如果方法體只有一條語句,大括號及分號也可以省略,如果有return的話也需要省略
最後我們演示一下有參數並且有返回值的寫法。
//創建一個Person類
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public Integer getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//測試類
public class Demo {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("張三",20));
list.add(new Person("李四",18));
list.add(new Person("王五",25));
//原始方式,對數組進行排序
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getAge() - o1.getAge();
}
});
System.out.println("=============Lambda表達式=============");
//Lambda方式
Collections.sort(list, (o1, o2)-> {
return o2.getAge() - o1.getAge();
});
System.out.println("=============Lambda表達式最終簡化=============");
//Lambda方式最終版,當參數只有一個的時候小括號也可以不寫
Collections.sort(list,(o1, o2) -> o2.getAge() - o1.getAge());
}
}
結果:
[Person{name='王五', age=25}, Person{name='張三', age=20}, Person{name='李四', age=18}]
當一個接口中只有一個抽象方法,並且作爲方法參數時也可以使用Lambda表達式簡化
這種情況下也可以使用Lambda表達式:
//只有一個抽象方法的接口
public interface Work {
void work();
}
//測試類
public class Test {
public static void main(String[] args) {
//原始
method(new Work() {
@Override
public void work() {
System.out.println("我喜歡工作!");
}
});
//Lambda
method(()->{
System.out.println("我喜歡工作!");
});
//Lambda最簡化
method(()-> System.out.println("我喜歡工作!"));
}
//該方法的參數是接口,該接口中就一個抽象方法
private static void method(Work work){
work.work();
}
}
下一篇是Stream流,這個流跟IO流完全不一樣,它也是JDK1.8以後的新特性之一。