java8開始,提供了函數(shù)式編程的功能,相關(guān)的接口有Consumer,Function等等.
我們先看一下Consumer的接口
void accept(T t);
//
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
如何使用?
假設(shè)我們有一個(gè)簡(jiǎn)單的需求,我們要把一個(gè)數(shù)組給打印出來
public static void print(List<Integer> list) {
System.out.println(list);
}
過了一段時(shí)間,產(chǎn)品又提了個(gè)新需求,需要用分號(hào)把數(shù)組隔開,之前的功能還要保留.于是你又得寫一個(gè)方法.
public static void print(List<Integer> list) {
String s = Joiner.on("-").join(list);
System.out.println(s);
}
如果產(chǎn)品又提了個(gè)需求,需要用*號(hào)隔開呢?
public static void print(List<Integer> list) {
String s = Joiner.on("*").join(list);
System.out.println(s);
}
如果又來一個(gè)需求呢?需要把這些打印好的數(shù)組發(fā)給第三方,那么是不是又得改代碼呢?
其實(shí)本質(zhì)的問題是,我們沒有把變化封裝出來,抽象的不夠.
那么該怎么修改呢?我們就要用到Consumer了.
我們先實(shí)現(xiàn)一個(gè)打印的方法.這個(gè)方法可以不做任何事.只是提供出來調(diào)用.
public static void print(Consumer<List<Integer>> consumer,List<Integer> list) {
consumer.accept(list);
}
這個(gè)方法沒有任何的業(yè)務(wù)邏輯,當(dāng)你需要調(diào)用的時(shí)候,你傳一個(gè)lambada進(jìn)來,你就可以自定義實(shí)現(xiàn).
static Consumer<List<Integer>> printRaw = System.out::println;
static Consumer<List<Integer>> printWithDot = list -> {
String s = Joiner.on("-").join(list);
System.out.println(s);
};
print(printRaw, Arrays.asList(1, 2, 3, 4, 5));
print(printWithDot, Arrays.asList(1, 2, 3, 4, 5));
這樣不管你需求再這么變化,print這個(gè)元方法都無需任何改變,因?yàn)樽兓狞c(diǎn)已經(jīng)被我們提取出來了.因?yàn)閖ava的方法是無法作為參數(shù)傳入到另一個(gè)方法的,所有l(wèi)ambada就發(fā)揮作用了.這個(gè)只是一個(gè)簡(jiǎn)單的demo.我們看看工程里是如何實(shí)現(xiàn)的.
forEach
其實(shí)跟上面的demo很像,你可以自定義如何forEach.
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
那map其實(shí)也是一樣,只是Consumer接受參數(shù)處理,是無需返回的.map的參數(shù)是一個(gè)Function,把A映射到B然后返回B.
R apply(T t);
然后我們想想,我們用map的時(shí)候,是不是萬物皆可映射.我們慢慢的體會(huì)下吧.