lambda的使用
lambda表達式:
思想轉變:
函數式編程思想:不在乎過程的方式,不在乎對象是那個,只在乎返回結果(重結果,輕過程)
面向對象思想:找一個對象,去做事情(萬物皆對象)
轉變過程:
以多線程爲例:
使用普通方法進行多線程操作
爲了獲取Runnable
接口的實現對象,爲該接口定義一個實現類`RunnableImpl,設置線程任務
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println("多線程任務執行!");
}
}
然後創建該實現類的對象作爲Thread
類的構造參數:
public class Demo03ThreadInitParam {
public static void main(String[] args) {
Runnable task = new RunnableImpl();
new Thread(task).start();
}
}
使用匿名內部類
這個RunnableImpl
類只是爲了實現Runnable
接口而存在的,而且僅被使用了唯一一次,所以使用匿名內部類的語法即可省去該類的單獨定義,即匿名內部類:
public class Demo04ThreadNameless {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多線程任務執行!");
}
}).start();
}
}
使用lambda表達式
public class Demo04ThreadNameless {
public static void main(String[] args) {
new Thread(() -> System.out.println("多線程任務執行!")).start();
}
}
你會發現使用了lambda表達式的書寫代碼簡約而不簡單
Lambda標準格式
Lambda省去面向對象的條條框框,格式由3個部分組成:
- 一些參數
- 一個箭頭
- 一段代碼
Lambda表達式的標準格式爲:
(參數類型 參數名稱) -> { 代碼語句 }
格式說明:
- 小括號內的語法與傳統方法參數列表一致:無參數則留空;多個參數則用逗號分隔。
->
是新引入的語法格式,代表指向動作。- 大括號內的語法與傳統方法體要求基本一致。
- lambda特點:延遲執行。
Lambda的使用前提
Lambda的語法非常簡潔,完全沒有面向對象複雜的束縛。但是使用時有幾個問題需要特別注意:
- 使用Lambda必須具有接口,且要求接口中有且僅有一個抽象方法。
無論是JDK內置的Runnable
、Comparator
接口還是自定義的接口,只有當接口中的抽象方法存在且唯一時,纔可以使用Lambda。 - 使用Lambda必須具有上下文推斷。
也就是方法的參數或局部變量類型必須爲Lambda對應的接口類型,才能使用Lambda作爲該接口的實例。
備註:有且僅有一個抽象方法的接口,稱爲“函數式接口”。
@FunctionalInterface註解
與 @Override 註解的作用類似,Java 8中專門爲函數式接口引入了一個新的註解: @FunctionalInterface 。該注
解可用於一個接口的定義上:一旦使用該註解來定義接口,編譯器將會強制檢查該接口是否確實有且僅有一個抽象方法,否則將會報錯。需要注意的是,即使不使用該註解,只要滿足函數式接口的定義,這仍然是一個函數式接口,使用起來都一樣。
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
常用函數式接口
Supplier接口
java.util.function.Supplier 接口僅包含一個無參的方法: T get() 。由於這是一個函數式接口,這也就意味着對應的Lambda表達式需要“對外提供”一個符合泛型類型的對象數據。
作用:生產型接口,指定接口的泛型是什麼,就生產什麼類型的數據
Consumer接口
java.util.function.Consumer 接口則正好與Supplier接口相反,它不是生產一個數據,而是消費一個數據,
其數據類型由泛型決定。
抽象方法:accept
Consumer 接口中包含抽象方法 void accept(T t) ,意爲消費一個指定泛型的數據。
作用:消費性接口,泛型執行什麼類型,就可以使用accept消費什麼類型的數據
默認方法:andThen
如果一個方法的參數和返回值全都是 Consumer 類型,那麼就可以實現效果:消費數據的時候,首先做一個操作,
然後再做一個操作,實現組合。而這個方法就是 Consumer 接口中的default方法 andThen 。下面是JDK的源代碼:
Consummer<String> con1;
Consummer<String> con2;
String s="hello";
con1.accept(s);
con2.accept(s);
con1.andThen(con2).accept(s);
Predicate接口
作用:對某種類型的數據進行判斷,從而得到一個boolean值結果。
java.util.function.Predicate 接口。
抽象方法:test
Predicate 接口中包含一個抽象方法: boolean test(T t) 。用於條件判斷的場景:
默認方法:and ,有false則false
既然是條件判斷,就會存在與、或、非三種常見的邏輯關係。其中將兩個 Predicate 條件使用“與”邏輯連接起來實
現“並且”的效果時,可以使用default方法 and 。
p1.and(p2).test(S)
p1.test(s)&&p2.test(s)
默認方法:or 有true則true
與 and 的“與”類似,默認方法 or 實現邏輯關係中的“或”。
默認方法:negate 有true則false,有false則true
“與”、“或”已經瞭解了,剩下的“非”(取反)也會簡單。
Function接口
作用:接口用來根據一個類型的數據得到另一個類型的數據,前者稱爲前置條件,後者稱爲後置條件。
java.util.function.Function<T,R>
抽象方法:apply
Function 接口中最主要的抽象方法爲: R apply(T t) ,根據類型T的參數獲取類型R的結果。
使用的場景例如:將 String 類型轉換爲 Integer 類型。
默認方法:andThen
Function 接口中有一個默認的 andThen 方法,用來進行組合操作