CompletableFuture——基本用法demo,推荐收藏,需要时查阅!
目录
Future使用 demo
CompletableFuture
CompletableFuture的优点:
demo1:thenApply,进行变换
demo2:thenAccept,获取上一步结果,下一步使用
demo3:thenRun,不管上一步计算结果,直接执行下一步操作
demo4:thenCombine,结合两个异步返回的CompletionStage的结果,进行转换
demo5:结合两个异步返回的CompletionStage的结果,进行转换
demo6:runAfterBoth,两个CompletionStage都运行完后执行
demo7:applyToEither,谁计算的快,我就用那个CompletionStage的结果进行下一步的转化操作
demo8:acceptEither,谁计算的快,我就用那个CompletionStage的结果进行下一步的转化操作
demo9:runAfterEither,两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)
demo10:exceptionally,当运行时出现了异常,可以通过exceptionally进行补偿
demo11:whenComplete
前言:推荐大家收藏,遇到问题方便查阅,多看几次demo基本就懂怎么使用了。
Future使用 demo
ExecutorService executor = Executors.newFixedThreadPool(4);
// 定义任务:
Callable task = new Task();
// 提交任务并获得Future:
Future future = executor.submit(task);
// 从Future获取异步执行返回的结果:
String result = future.get(); // 可能阻塞
一个Future接口表示一个未来可能会返回的结果,它定义的方法有:
get():获取结果(可能会等待)get(long timeout, TimeUnit unit):获取结果,但只等待指定的时间;cancel(boolean mayInterruptIfRunning):取消当前任务;isDone():判断任务是否已完成。
JDK5新增了Future接口,用于描述一个异步计算的结果。虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果。
CompletableFuture
CompletableFuture的优点:
- 异步任务结束时,会自动回调某个对象的方法;
- 异步任务出错时,会自动回调某个对象的方法;
- 主线程设置好回调后,不再关心异步任务的执行。
如果只是实现了异步回调机制,我们还看不出CompletableFuture相比Future的优势。CompletableFuture更强大的功能是,多个CompletableFuture可以串行执行。
demo1:thenApply,进行变换
public CompletionStage thenApply(Function super T,? extends U> fn);
public CompletionStage thenApplyAsync(Function super T,? extends U> fn);
public CompletionStage thenApplyAsync(Function super T,? extends U> fn,Executor executor);
首先说明一下已Async结尾的方法都是可以异步执行的,如果指定了线程池,会在指定的线程池中执行,如果没有指定,默认会在ForkJoinPool.commonPool()中执行,下文中将会有好多类似的,都不详细解释了。关键的入参只有一个Function,它是函数式接口,所以使用Lambda表示起来会更加优雅。它的入参是上一个阶段计算后的结果,返回值是经过转化后结果。
例如:
@Testpublic void thenApply() {String result = CompletableFuture.supplyAsync(() -> "hello").thenApply(s -> s + " world").join();System.out.println(result);}
结果为:
hello world
demo2:thenAccept,获取上一步结果,下一步使用
public CompletionStage thenAccept(Consumer super T> action);
public CompletionStage thenAcceptAsync(Consumer super T> action);
public CompletionStage thenAcceptAsync(Consumer super T> action,Executor executor);
thenAccept是针对结果进行消耗,因为他的入参是Consumer,有入参无返回值。例如:
@Test
public void thenAccept(){ CompletableFuture.supplyAsync(() -> "hello").thenAccept(s -> System.out.println(s+" world"));
}
结果为:
hello world
demo3:thenRun,不管上一步计算结果,直接执行下一步操作
public CompletionStage thenRun(Runnable action);
public CompletionStage thenRunAsync(Runnable action);
public CompletionStage thenRunAsync(Runnable action,Executor executor);
thenRun它的入参是一个Runnable的实例,表示当得到上一步的结果时的操作。
例如:
@Testpublic void thenRun(){CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "hello";}).thenRun(() -> System.out.println("hello world"));while (true){}}
结果为:
hello world
demo4:thenCombine,结合两个异步返回的CompletionStage的结果,进行转换
public CompletionStage thenCombine(CompletionStage extends U> other,BiFunction super T,? super U,? extends V> fn);
public CompletionStage thenCombineAsync(CompletionStage extends U> other,BiFunction super T,? super U,? extends V> fn);
public CompletionStage thenCombineAsync(CompletionStage extends U> other,BiFunction super T,? super U,? extends V> fn,Executor executor);
它需要原来的处理返回值,并且other代表的CompletionStage也要返回值之后,利用这两个返回值,进行转换后返回指定类型的值。例如:
@Testpublic void thenCombine() {String result = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "hello";}).thenCombine(CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "world";}), (s1, s2) -> s1 + " " + s2).join();System.out.println(result);}
执行时间为5秒,上一个结果执行完后,执行下一个,然后合并,结果为:
hello world
demo5:结合两个异步返回的CompletionStage的结果,进行转换
public CompletionStage thenAcceptBoth(CompletionStage extends U> other,BiConsumer super T, ? super U> action);
public CompletionStage thenAcceptBothAsync(CompletionStage extends U> other,BiConsumer super T, ? super U> action);
public CompletionStage thenAcceptBothAsync(CompletionStage extends U> other,BiConsumer super T, ? super U> action, Executor executor);
它需要原来的处理返回值,并且other代表的CompletionStage也要返回值之后,利用这两个返回值,进行消耗。
例如:
@Testpublic void thenAcceptBoth() {CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "hello";}).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "world";}), (s1, s2) -> System.out.println(s1 + " " + s2));while (true){}}
执行时间为5秒,结果为:
hello world
demo6:runAfterBoth,两个CompletionStage都运行完后执行
public CompletionStage runAfterBoth(CompletionStage> other,Runnable action);
public CompletionStage runAfterBothAsync(CompletionStage> other,Runnable action);
public CompletionStage runAfterBothAsync(CompletionStage> other,Runnable action,Executor executor);
不关心这两个CompletionStage的结果,只关心这两个CompletionStage执行完毕,之后在进行操作(Runnable)。例如:
@Testpublic void runAfterBoth(){CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "s1";}).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "s2";}), () -> System.out.println("hello world"));while (true){}}
结果为
hello world
demo7:applyToEither,谁计算的快,我就用那个CompletionStage的结果进行下一步的转化操作
public CompletionStage applyToEither(CompletionStage extends T> other,Function super T, U> fn);
public CompletionStage applyToEitherAsync(CompletionStage extends T> other,Function super T, U> fn);
public CompletionStage applyToEitherAsync(CompletionStage extends T> other,Function super T, U> fn,Executor executor);
我们现实开发场景中,总会碰到有两种渠道完成同一个事情,所以就可以调用这个方法,找一个最快的结果进行处理。例如:
@Testpublic void applyToEither() {String result = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "s1";}).applyToEither(CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "hello world";}), s -> s).join();System.out.println(result);}
结果为:
hello world
demo8:acceptEither,谁计算的快,我就用那个CompletionStage的结果进行下一步的转化操作
public CompletionStage acceptEither(CompletionStage extends T> other,Consumer super T> action);
public CompletionStage acceptEitherAsync(CompletionStage extends T> other,Consumer super T> action);
public CompletionStage acceptEitherAsync(CompletionStage extends T> other,Consumer super T> action,Executor executor);
例如:
@Testpublic void acceptEither() {CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "s1";}).acceptEither(CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "hello world";}), System.out::println);while (true){}}
结果为:
hello world
demo9:runAfterEither,两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)
public CompletionStage runAfterEither(CompletionStage> other,Runnable action);
public CompletionStage runAfterEitherAsync(CompletionStage> other,Runnable action);
public CompletionStage runAfterEitherAsync(CompletionStage> other,Runnable action,Executor executor);
例如:
@Testpublic void runAfterEither() {CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "s1";}).runAfterEither(CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "s2";}), () -> System.out.println("hello world"));while (true) {}}
结果为:
hello world
demo10:exceptionally,当运行时出现了异常,可以通过exceptionally进行补偿
public CompletionStage exceptionally(Function fn);
例如:
@Testpublic void exceptionally() {String result = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}if (1 == 1) {throw new RuntimeException("测试一下异常情况");}return "s1";}).exceptionally(e -> {System.out.println(e.getMessage());return "hello world";}).join();System.out.println(result);}
结果为:
java.lang.RuntimeException: 测试一下异常情况
hello world
demo11:whenComplete
当运行完成时,对结果的记录。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。这里为什么要说成记录,因为这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常。所以不会对结果产生任何的作用。
public CompletionStage whenComplete(BiConsumer super T, ? super Throwable> action);
public CompletionStage whenCompleteAsync(BiConsumer super T, ? super Throwable> action);
public CompletionStage whenCompleteAsync(BiConsumer super T, ? super Throwable> action,Executor executor);
例如:
@Testpublic void whenComplete() {String result = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}if (1 == 1) {throw new RuntimeException("测试一下异常情况");}return "s1";}).whenComplete((s, t) -> {System.out.println(s);System.out.println(t.getMessage());}).exceptionally(e -> {System.out.println(e.getMessage());return "hello world";}).join();System.out.println(result);}
结果为:
null
java.lang.RuntimeException: 测试一下异常情况
java.lang.RuntimeException: 测试一下异常情况
hello world
这里也可以看出,如果使用了exceptionally,就会对最终的结果产生影响,它没有口子返回如果没有异常时的正确的值,这也就引出下面我们要介绍的handle。
demo12:handle
运行完成时,对结果的处理。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。
public CompletionStage handle(BiFunction super T, Throwable, ? extends U> fn);
public CompletionStage handleAsync(BiFunction super T, Throwable, ? extends U> fn);
public CompletionStage handleAsync(BiFunction super T, Throwable, ? extends U> fn,Executor executor);
例如:
出现异常时
@Testpublic void handle() {String result = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}//出现异常if (1 == 1) {throw new RuntimeException("测试一下异常情况");}return "s1";}).handle((s, t) -> {if (t != null) {return "hello world";}return s;}).join();System.out.println(result);}
结果为:
hello world
未出现异常时
@Testpublic void handle() {String result = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "s1";}).handle((s, t) -> {if (t != null) {return "hello world";}return s;}).join();System.out.println(result);}
结果为:
s1
上面就是CompletionStage接口中方法的使用实例,CompletableFuture同样也同样实现了Future,所以也同样可以使用get进行阻塞获取值,总的来说,CompletableFuture使用起来还是比较爽的,看起来也比较优雅一点。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
