一 前言
節(jié)前買了一本《Java8實(shí)戰(zhàn)》的書(shū),大概瀏覽了一下,其實(shí)主要講的是Java8的函數(shù)式編程,由于我們項(xiàng)目用RxJava和Scala,所以基本上了解函數(shù)式編程和命令式編程的區(qū)別。接下來(lái)幾篇博客都是以筆記的形式記錄書(shū)中內(nèi)容。
放假期間詳細(xì)看了第一部分內(nèi)容(包括前三章),主要說(shuō)的是Lambda表達(dá)式(這個(gè)是借鑒了C#,Python和Scala等語(yǔ)言的特性),引入這個(gè)就是為了語(yǔ)法的簡(jiǎn)潔。
現(xiàn)在通過(guò)書(shū)中代碼例子梳理一下幾個(gè)主要概念:行為參數(shù)化(behavior parameterization)、匿名類(Anonymous class),Lambda 表達(dá)式(Lambda expressions)、函數(shù)式接口(Functional interface)和方法引用(Method reference)等幾個(gè)重要概念。
二 項(xiàng)目需求變化
老家種了幾畝蘋(píng)果,今年大豐收,我們把這些蘋(píng)果數(shù)據(jù)信息化。
# 定義一個(gè)蘋(píng)果數(shù)據(jù)集合
List<Apple> inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red"));
2.1 第一個(gè)需求,篩選出綠色的蘋(píng)果
這個(gè)很好實(shí)現(xiàn),就不多說(shuō)了。
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;
}
2.2 第二個(gè)需求,篩選紅色的蘋(píng)果
如果過(guò)幾天需求有變了,要篩選黃色的蘋(píng)果,不只要復(fù)制多少次代碼,果斷把顏色作為參數(shù)。
public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getColor().equals(color)){
result.add(apple);
}
}
return result;
}
# 調(diào)用
List<Apple> greenApples = filterApplesByColor(inventory, "red");
2.3 第三個(gè)需求,篩選重量大于150g的蘋(píng)果。
一般的寫(xiě)法如下
public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getWeight() > weight){
result.add(apple);
}
}
return result;
}
# 調(diào)用
List<Apple> heavyApples = filterApplesByWeight(inventory, 150);
2.4 第四個(gè)需求,篩選重量大于150g和紅色蘋(píng)果
同志們繼續(xù)重構(gòu),定義兩個(gè)參數(shù)
public static List<Apple> filterApples(List<Apple> inventory, String color,int weight){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getWeight() > weight||apple.getColor().equals(color){
result.add(apple);
}
}
return result;
}
#調(diào)用
List<Apple> redApples = filterApples(inventory, "red",150);
三 代碼重構(gòu)
上面的需求很會(huì)變,如果客戶需要篩選形狀和產(chǎn)地時(shí),需要繼續(xù)重構(gòu)
面向接口編程,封裝行為,進(jìn)行行為參數(shù)化,其實(shí)就是策略模式。
3.1 行為參數(shù)化(behavior parameterization)
# 定義個(gè)接口(只定義一個(gè)抽象方法的接口叫函數(shù)式接口)
interface ApplePredicate{
public boolean test(Apple a);
}
# 實(shí)現(xiàn)過(guò)濾重量行為的類
static class AppleWeightPredicate implements ApplePredicate{
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
}
# 實(shí)現(xiàn)篩選顏色行為的類
static class AppleColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "green".equals(apple.getColor());
}
}
# 調(diào)用
public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}
3.2 匿名類(Anonymous class)
上面的代碼還有點(diǎn)啰嗦,能不能再簡(jiǎn)單一點(diǎn),使用匿名類
List<Apple> redApples2 = filter(inventory, new ApplePredicate() {
public boolean test(Apple a){
return a.getColor().equals("red");
}
});
3.3 使用Lambda 表達(dá)式
java 8引入了Lambda表達(dá)式,不用像匿名類那樣,每個(gè)行為都寫(xiě)一個(gè)類模板,接下來(lái)我們繼續(xù)簡(jiǎn)化代碼。
List<Apple> greenApples = filter(inventory, (Apple a) -> "green".equals(a.getColor()));
3.4 使用方法引用更易讀,更自然
上面的Lambda表達(dá)式代表了直接調(diào)用類的方法,方法引用被看做針對(duì)僅僅涉及單一方法的Lambda的語(yǔ)法糖。
有三種方式構(gòu)建方法引用
- 指向靜態(tài)方法的方法引用(例如Integer的parseInt方法,寫(xiě)作Integer::parseInt)。
- 指向任意類型實(shí)例方法的方法引用(假設(shè)(String s)->s.toUpperCase()可以寫(xiě)作String::toUpperCase)
- 指向現(xiàn)有對(duì)象的實(shí)例方法引用(假設(shè)你有一個(gè)局部變量Local local,用于存放Local類型對(duì)象。它有一個(gè)getValue(),則寫(xiě)法為local::getValue)
—— Java 8實(shí)戰(zhàn)
上面代碼的簡(jiǎn)化,就是第一種構(gòu)建方式,如下:
List<Apple> greenApples = filter(inventory, String::equals);
四 Java8 常用的函數(shù)式接口
Java8中對(duì)函數(shù)式接口的描述是只定義一個(gè)抽象方法的接口叫函數(shù)式接口。
| 函數(shù)式接口 | 函數(shù)描述符 | 原始類型特化 |
|---|---|---|
| Predicate<T> | T >boolean | IntPredicate,LongPredicate,DoublePredicate |
| Consumer<T> | T->void | IntConsumer,LongConsumer,DoubleConsumer |
| Function<T,R> | T->R | IntFunction<R>,IntToDoubleFunction .... |
| Supplier<T> | ()->T | BooleanSupplier,IntSupplier,LongSupplier |
| UnaryOperator<T> | T->T | IntUnaryOperator,LongUnaryOperator |
| BinaryOperator | (T,T)->T | IntBinaryOperator,LongBinaryOperator |
參考文獻(xiàn)
[1]《Java 8實(shí)戰(zhàn)》