最近遇到一个场景,有一串数据,需要经过很多步骤加工处理,取成功的数据再往下一个步骤传,写了代码之后感觉很绕,于是想到了类似于流水线的思路。在经过一系列的搜索后,发现java8中的Function函数里的compose(),andThen()函数很适合。
compose()
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
看方法,可以知道,是传入一个function,先计算传入的function得到结果,再将结果传到外部的Function进行使用。
andThen()
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
这个和compose,是相反的。见名知意,先计算本身Function函数,将得到的结果传入到参数传入的after函数中作为参数。
有了这两个方法,就可以很方便的实现我们简单的链式调用,隐藏了中间的数据。极大的提升了代码的简介性:
public static void main(String[] args) {
List<Integer> initData = IntStream.range(0, 20).boxed().collect(Collectors.toList());
List<Integer> firRet = removeHandler(initData);
System.out.println("第一次处理的结果:" + firRet.size());
List<Integer> secRet = addHandler(firRet);
System.out.println("第二次处理的结果:" + secRet.size());
List<Integer> thirdRet = addHandler(firRet);
System.out.println("第三次处理的结果:" + thirdRet.size());
List<Integer> fourRet = removeHandler(firRet);
System.out.println("第四次处理的结果:" + fourRet.size());
List<Integer> fiveRet = removeHandler(firRet);
System.out.println("第五次处理的结果:" + fiveRet.size());
}
private static List<Integer> removeHandler(List<Integer> dataList){
// 每次随机删除几个数
System.out.println("删除一些数据。。");
return handler((i,list) -> list.remove(i), dataList);
}
private static List<Integer> addHandler(List<Integer> dataList){
// 每次随机增加几个数,
System.out.println("增加一些数据。。");
return handler((i,list) -> list.add(i), dataList);
}
private static List<Integer> handler(BiConsumer<Integer, List<Integer>> consumer, List<Integer> dataList){
List<Integer> handList = new ArrayList<>(dataList);
// 处理逻辑,每次随机处理几个数据
IntStream.range(0, getRandom(5)).boxed().forEach(i -> consumer.accept(getRandom(handList.size()), handList));
// 错误数据可以自行处理,这里返回的是成功的数据
return handList;
}
private static Integer getRandom(Integer size){
return new Random().nextInt(size);
}
执行结果:
这里我每次进行逻辑处理之后都需要将上一步的结果保存下来,放到下一步的入参,显得很多余。也不怎么好看,在多的时候,多种调用的时候容易传错参数。接下来换成java8的方式,链路调用
public static void main(String[] args) {
List<Integer> initData = IntStream.range(0, 20).boxed().collect(Collectors.toList());
Function<List<Integer>, List<Integer>> remove = FunctionTest::removeHandler;
Function<List<Integer>, List<Integer>> add = FunctionTest::addHandler;
List<Integer> result = add.compose(remove)
.andThen(add)
.andThen(remove)
.andThen(remove)
.apply(initData);
System.out.println("调整后的:" + result);
}
执行结果:
可以看到使用函数调用的方式,很简洁,对于调用一目了然。