自从java8引入了Stream、函数式编程、CompletableFuture等特性之后,给我们码代码提供了不少酷炫的操作。从JDK1.5开始我们就可以通过Future接口实现异步,主要是创建一个线程池,然后提交Runnable或者Callable的任务。然后可以用get来获取返回结果(执行完毕才会返回),传统回调最大的问题就是不能将控制流分离到不同的事件处理器中。而CompletableFuture弥补了缺陷。本文主要讲CompletableFuture相关的特性。
根据下面这行代码可以看出CompletableFuture实现了Future,CompletionStage。说明CompletableFuture既有保留了Future的特性,又通过CompletableFuture进行了扩展。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
1.函数式接口
观察CompletableFuture代码,可以看出方法参数都是函数式接口,这个比较切合jdk1.8的编码风格。因此,我们可以先了解一下何为函数式编程。函数式编程就是通过lambda表达式进行简化编码。符合函数编程的接口叫函数式接口,函数式接口有一个特性,就是只能有一个抽象方法,在jdk1.8中函数式接口除了仅有的一个抽象方法,还可以拥有default缺省方法或者static静态方法。以下介绍几个函数式接口。
1.Function<T, R>:一个输入一个返回,stream中的map方法的入参就是该函数式接口
该接口的核心抽象方法:R apply(T t);调用该方法的输入参数是T,返回结果是R。示例如下:
public static void main(String[] args){
Function<String,Integer> function = a->{
return Integer.parseInt(a);
};
System.out.println(function.apply("5"));
}
2.Supplier<T>:没有输入,有一个返回
该接口的核心抽象的方法:T get();示例如下:
Supplier<Integer> supplier = ()->{
return 5;
};
System.out.println(supplier.get());
3.Predicate<T>:一个输入参数,返回布尔值,stream中该函数式接口作为filter的入参。
该接口的核心抽象的方法:boolean test(T t);示例如下:
Predicate<Integer> predicate = a->{
return a==5;
};
System.out.println(predicate.test(5));
4.Consumer<T>:一个输入,没有返回,stream中的foreach使用该接口作为输入。
该接口的核心的方法是:void accept(T t);示例如下:
Consumer<Integer> consumer = a->{
System.out.println(a);
};
consumer.accept(5);
5.BiConsumer<T, U>:两个输入,没有输出。同Consumer<T>,区别在于输入参数个数不同。
示例如下:
BiConsumer<Integer,Integer> biConsumer = (a,b)->{
System.out.println(a+b);
};
biConsumer.accept(5,3);
6.BiFunction<T, U, R>:两个输入,有输出。同Function<T,R>,区别在于输入参数个数不同。
BiFunction<Integer,Integer,String> biFunction = (a,b)->{
return String.valueOf(a+b);
};
System.out.println(biFunction.apply(4,5));
2.CompletableFuture实战