java8开始,提供了函数式编程的功能,相关的接口有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); };
}
如何使用?
假设我们有一个简单的需求,我们要把一个数组给打印出来
public static void print(List<Integer> list) {
System.out.println(list);
}
过了一段时间,产品又提了个新需求,需要用分号把数组隔开,之前的功能还要保留.于是你又得写一个方法.
public static void print(List<Integer> list) {
String s = Joiner.on("-").join(list);
System.out.println(s);
}
如果产品又提了个需求,需要用*号隔开呢?
public static void print(List<Integer> list) {
String s = Joiner.on("*").join(list);
System.out.println(s);
}
如果又来一个需求呢?需要把这些打印好的数组发给第三方,那么是不是又得改代码呢?
其实本质的问题是,我们没有把变化封装出来,抽象的不够.
那么该怎么修改呢?我们就要用到Consumer了.
我们先实现一个打印的方法.这个方法可以不做任何事.只是提供出来调用.
public static void print(Consumer<List<Integer>> consumer,List<Integer> list) {
consumer.accept(list);
}
这个方法没有任何的业务逻辑,当你需要调用的时候,你传一个lambada进来,你就可以自定义实现.
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这个元方法都无需任何改变,因为变化的点已经被我们提取出来了.因为java的方法是无法作为参数传入到另一个方法的,所有lambada就发挥作用了.这个只是一个简单的demo.我们看看工程里是如何实现的.
forEach
其实跟上面的demo很像,你可以自定义如何forEach.
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
那map其实也是一样,只是Consumer接受参数处理,是无需返回的.map的参数是一个Function,把A映射到B然后返回B.
R apply(T t);
然后我们想想,我们用map的时候,是不是万物皆可映射.我们慢慢的体会下吧.