Java 8 實(shí)戰(zhàn)學(xué)習(xí)
java 8 已經(jīng)出來(lái)和長(zhǎng)時(shí)間了发笔,作為一個(gè) AndroidDevepler 來(lái)說的現(xiàn)在還沒有機(jī)會(huì)在 studio 直接使用 java8 的新特性漂彤,但是谷歌官方宣布 AndroidStudio 2.4 以后就可以支持 java8 的一些新特性輕重就包括 lambda 毛萌,關(guān)于 java8 網(wǎng)上有很多教程历恐,但是「書中得來(lái)終覺淺买置,覺知此時(shí)要躬行」瓶蚂,所以我決定把 《 Java8 實(shí)戰(zhàn) 》親自閱讀實(shí)踐一下。
行為參數(shù)化
書中通過 普通實(shí)現(xiàn) -> 抽取行為參數(shù) -> 匿名內(nèi)部類實(shí)現(xiàn)這個(gè)具體行為 -> 引入 lambda 表達(dá)式讓代碼更簡(jiǎn)潔 夏跷。 來(lái)幫助我們理解 lambda 的由來(lái)哼转。
普通實(shí)現(xiàn)
書中列舉了根據(jù)不同條件篩選蘋果的例子:起初我們?nèi)绻枰Y選蘋果的顏色我們會(huì)這么寫:
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if ("green".equals(apple.getColor())){
result.add(apple);
}
} return result;
}
如果我們需要篩選蘋果的重量我們需要這么寫:
public static List<Apple> filterWeightApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getWeight() > 10){
result.add(apple);
}
} return result;
}
這樣看起來(lái)代碼就很冗余,必定不同連個(gè)代碼不同之處就是 『篩選的行為的條件』 不同槽华,按照面向?qū)ο蟮乃枷耄骸敢粋€(gè)良好的原則是在編寫類似的代碼之后壹蔓,嘗試將其抽象化」。
篩選條件抽取為接口
所以我們將篩選條件抽取為一個(gè)參數(shù)猫态,該參數(shù)由一個(gè)抽象的接口承擔(dān):
public interface ApplePredicate{
boolean test (Apple apple);
}
該接口的 test 方法即為蘋果篩選的條件佣蓉,具體篩選的邏輯由這個(gè)接口的實(shí)現(xiàn)來(lái)決定。是不是覺得很熟悉亲雪,我們最常用的 onClick 事件勇凭,就是這樣的一個(gè)接口。這樣以后我們的 filterApples的方法就可以修改為下面的實(shí)現(xiàn):
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (p.test(apple)) { // 謂詞對(duì)象p封裝了,測(cè)試蘋果的條件
result.add(apple);
}
} return result;
}
我們下面在使用的 filterApples 的時(shí)候就只需關(guān)注 ApplePredicate 的實(shí)現(xiàn)就好了义辕。表面上看我們?cè)诘墓ぷ魇?ApplePredicate 的實(shí)現(xiàn)虾标,其實(shí)我們?cè)诔橄?filterApples 的時(shí)候就做到了:
filterApples 方法的行為取決于你通過 ApplePredicate 對(duì)象傳遞的代碼。換句話說灌砖,你把 filterApples 方法的行為參數(shù)化了璧函!
原翻譯中 filterApples 方法的行為參數(shù)化,我感覺翻譯為 filterApples 的「篩選行為」參數(shù)話了比較好基显。
通過匿名內(nèi)部類來(lái)減少不必要的接口實(shí)現(xiàn)類
但是這樣雖然我們完成了篩選條件的參數(shù)化蘸吓,但是問題是這樣每次我們都要實(shí)現(xiàn)這樣的一個(gè) ApplePredicate 具體實(shí)現(xiàn)類,在 lambda 出現(xiàn)之前我們是使用匿名內(nèi)部類來(lái)解決的续镇。
List<Apple> redApples = filterApples(inventory, new ApplePredicate() {
public boolean test(Apple apple) {
return "red".equals(apple.getColor());
}
});
那么這樣的還是不太令人滿意美澳,因?yàn)槲覀冎?ApplePredicate 是 filterApples 的第二個(gè)參數(shù)(可推敲),真正需要我們決定的實(shí)現(xiàn)條件是 "red".equals(apple.getColor()
,如果我們能直接傳遞這句話制跟,來(lái)替代這些大括號(hào)就好了舅桩。用原書的話說就是:
即使匿名類處理在某種程度上改 善了為一個(gè)接口聲明好幾個(gè)實(shí)體類的 啰 嗦問題,但它仍不能令人滿意雨膨。在只需要傳遞一段簡(jiǎn)單的 代碼時(shí)(例如表示選擇標(biāo)準(zhǔn)的boolean表達(dá)式)擂涛,你還是要?jiǎng)?chuàng)建一個(gè)對(duì)象,明確地實(shí)現(xiàn)一個(gè)方法 來(lái)定義一個(gè)新的行為(例如Predicate中的test方法或是EventHandler中的handler方法)聊记。
如果我們使用 lambda 表達(dá)式來(lái)實(shí)現(xiàn)上邊的邏輯撒妈,看上去將會(huì)很清爽:
List<Apple> filterApple = filterApple(apples, (Apple apple) -> "red".equals(apple.getColor()));
函數(shù)接口的概念
書中第二章并沒有具體展開說明 lambda 表達(dá)式的使用,而是引入了 「行為參數(shù)化」 這個(gè)概念排监。 這個(gè)概念作為一個(gè) AndroidDeveloper 我們幾乎每天都在使用狰右。 比如: 網(wǎng)絡(luò)接口的回調(diào) CallBack 接口, 比如 setOnClickListener 中要傳遞的 View.OnClickListener 的接口舆床。此類接口在java用有一個(gè)專有的名詞就做函數(shù)接口:
Single Abstract Method interfaces 當(dāng)然首先是一個(gè)接口棋蚌,然后就是在這個(gè)接口里面只能有一個(gè)抽象方法
java 8 之前已經(jīng)有的函數(shù)接口
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
java8 新定義的函數(shù)式接口: java.util.function 中定義了幾組類型的函數(shù)式接口以及針對(duì)基本數(shù)據(jù)類型的子接口:
Predicate -- 傳入一個(gè)參數(shù),返回一個(gè)bool結(jié)果挨队, 方法為boolean test(T t)
Consumer -- 傳入一個(gè)參數(shù)谷暮,無(wú)返回值,純消費(fèi)盛垦。 方法為void accept(T t) 如:List.forEach(Consumer c) 方法
Function -- 傳入一個(gè)參數(shù)湿弦,返回一個(gè)結(jié)果,方法為R apply(T t)
Supplier -- 無(wú)參數(shù)傳入腾夯,返回一個(gè)結(jié)果颊埃,方法為T get()
UnaryOperator -- 一元操作符, 繼承Function,傳入?yún)?shù)的類型和返回類型相同蝶俱。
BinaryOperator -- 二元操作符竟秫, 傳入的兩個(gè)參數(shù)的類型和返回類型相同, 繼承BiFunction
這一章我們主要了解了什么是函數(shù)式接口并引入了 lambda 可以解決函數(shù)式接口以及匿名內(nèi)部類實(shí)現(xiàn)的啰嗦跷乐,在下一偏我們將學(xué)習(xí) lambda 可以解決哪些,以及如何解決這個(gè)啰嗦的問題趾浅。