表達式組成:
(parameters)->expression
(parameters)->{statements;},例如:
示例1:(String s)->s.length()
具有一個String類型的參數並返回一個int類型。Lambda沒有return語句,因爲已經隱含了return。
示例2:(Apple a)->a.getWeight()>150
有一個Apple類型的參數並返回一個boolean類型。
示例3:(int x,int y)->{
System.out.println(“result:”+i);
System.out.println(x+y);
}具有兩個int類型的參數而沒有返回值,Lambda表達式可以包含多行語句。
示例4:()->42
表達式沒有參數,返回一個int類型。
示例5:(Apple a1,Apple a2)->
a1.getWeight().compareTo(a2.getWeight())
表達式具有兩個Apple類型的參數,並返回一個int類型。
Lambda表達式允許你直接以內聯的形式爲函數式接口的抽象方法提供實現,並把整個表達式作爲函數式接口的實例。(函數式接口指的是僅僅有一個方法的interface接口,這裏表達的意思是Lambda可以作爲接口的匿名內部類)
函數式接口的抽象方法的簽名基本上就是Lambda表達式的簽名,我們將這種抽象方法叫做函數描述符。(意思就是interface中方法的參數類型、參數數量、返回值要跟Lambda表達式中的完全一致,想想也是,畢竟是要作爲接口默認實現的,沒辦法)
Runnable r1 = ()->System.out.println
(“Hello World!”);
prcess(r1);
process(()->System.out.println(“Hello World!”));
由於Runnable是個接口且該接口只有一個方法,所以可以用Lambda來創建實例。
工具類
java.util.function.Predicate<T>接口定義了一個名叫test的抽象方法,該方法接受泛型T對象並返回一個boolean類型,該接口適用於涉及類型T的布爾表達式。(就是參數需要boolean值時可以用該接口,下面類似)
java.util.function.Consumer<T>定義一個accept抽象方法,接受泛型T的對象且沒有返回void。
java.util.function.Function<T,R>定義一個叫做apply的方法,接受一個泛型T的對象並返回一個泛型R的對象。
Lambda引用外部變量
int port = 1337;
Runnable r = ()->System.out.println(port);
注意:局部變量必須是顯式聲明爲final或事實上的final。
爲什麼會有這個限制?假如port變量在線程A中,Lambda則可能在線程B上,此時線程B去訪問線程A的時候port可能已經不存在了,爲了避免這種情況發生,線程B存有port變量的一份拷貝副本,既然是副本,那就存在着副本與原件的問題,採用final變量則能保證副本與原件的一致性。
方法引用
方法引用可以被看作僅僅調用特定方法的Lambda的一種快捷寫法。基本思想就是如果一個Lambda代表的只是“直接調用這個方法”,那最好還是用名稱來調用它,而不是去描述如何調用它。
使用方法引用時,目標引用放在分隔符::前面,方法名稱放在::後面,例如:
(App a)->a.getW()等價於App::getW
(str,i)->str.substring(i)等價於String::substring
(String s)->System.out.println(s)等價於System.out::println
靜態方法的引用
Lambda:
(args)->ClassName.staticMethod(args)
方法引用:
ClassName::staticMethod
實例方法的引用
①Lambda:
(arg,rest)->arg.instanceMethod(rest)
方法引用:arg是ClassName類型
ClassName::instanceMethod
②Lambda:(arg)->expr.instanceMethod(arg)
方法引用:
expr::instanceMethod
③注意:第一個與第二個區別在於第一個是調用參數的實例方法,第二個是調用外部變量的實例方法。
構造方法引用
用類名稱和關鍵字new來創建一個應用:ClassName::new。
調用無參的構造方法
Supplier<App> c1=App::new;
App a1=c1.get();
通過::new來指向App的默認構造方法,然後通過Supplier的get方法來產生一個新的App。
調用一個參數的構造方法
java.util.function.Function<Integer,App> c1=App:new;
App a1=c1.apply(1);
由於java.util.function.Function<T,R>定義一個叫做apply的方法,接受一個泛型T的對象並返回一個泛型R的對象,也就是通過Function的apply來間接生成App對象。
調用兩個參數的構造方法
java.util.function.BiFunction<String,Integer,App> c1=App:new;
App a1=c1.apply(“test”,10);
總結
靜態方法調用爲ClassName::staticMethod
構造方法調用爲ClassName::new
假如某個ClassName的構造方法有N個參數的話,那就需要自己去創建一個與ClassName的構造方法的簽名匹配的函數式接口,例如:App的構造方法是5個參數,可以這樣:
public interface TFunction<T,U,V,App>{
App apply(T t,U u,V v);
}
(parameters)->expression中只要parameters數量、類型以及expression返回值與XX方法簽名匹配就行,不在乎方法是哪個ClassName的。