行爲參數化&Lambda表達式

表達式組成:

(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的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章