转 http://www.jianshu.com/p/6f3ee90ab7d3

CompletableFuture类实现了CompletionStage和Future接口。Future是Java 5添加的类,用来描述一个异步计算的结果,但是获取一个结果时方法较少,要么通过轮询isDone,确认完成后,调用get()获取值,要么调用get()设置一个超时时间。但是这个get()方法会阻塞住调用线程,这种阻塞的方式显然和我们的异步编程的初衷相违背。
为了解决这个问题,JDK吸收了guava的设计思想,加入了Future的诸多扩展功能形成了CompletableFuture。

CompletionStage是一个接口,从命名上看得知是一个完成的阶段,它里面的方法也标明是在某个运行阶段得到了结果之后要做的事情。

  1. 进行变换

    public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
    public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);
    public <U> CompletionStage<U> 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
  2. 进行消耗

    public CompletionStage<Void> thenAccept(Consumer<? super T> action);
    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
    public CompletionStage<Void> 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
  3. 对上一步的计算结果不关心,执行下一个操作。
    public CompletionStage<Void> thenRun(Runnable action);
    public CompletionStage<Void> thenRunAsync(Runnable action);
    public CompletionStage<Void> 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

    4.结合两个CompletionStage的结果,进行转化后返回

    public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
    public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
    public <U,V> CompletionStage<V> 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);}

    结果为:

    hello world
  4. 结合两个CompletionStage的结果,进行消耗
    public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
    public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
    public <U> CompletionStage<Void> 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){}}

    结果为:

    hello world
  5. 在两个CompletionStage都运行完执行。
    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
    public CompletionStage<Void> 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

    6.两个CompletionStage,谁计算的快,我就用那个CompletionStage的结果进行下一步的转化操作。

    public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
    public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
    public <U> CompletionStage<U> 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
  6. 两个CompletionStage,谁计算的快,我就用那个CompletionStage的结果进行下一步的消耗操作。
    public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
    public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
    public CompletionStage<Void> 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
  7. 两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)。
    public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
    public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
    public CompletionStage<Void> 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
  8. 当运行时出现了异常,可以通过exceptionally进行补偿。
    public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> 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
  9. 当运行完成时,对结果的记录。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。这里为什么要说成记录,因为这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常。所以不会对结果产生任何的作用。
    public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
    public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
    public CompletionStage<T> 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。

  10. 运行完成时,对结果的处理。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。
    public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
    public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
    public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);

    例如:
    出现异常时

    @Test
    public 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

    未出现异常时

    @Test
    public 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使用起来还是比较爽的,看起来也比较优雅一点。

转载于:https://www.cnblogs.com/diegodu/p/7346760.html

CompletableFuture 详解相关推荐

  1. 【异步编程学习笔记】JDK中的FutureTask和CompletableFuture详解(使用示例、源码)

    文章目录 FutureTask概述 使用实例 类图结构 FutureTask的run()方法 FutureTask的局限性 CompletableFuture概述 CompletableFuture代 ...

  2. CompletableFuture详解~join与get的区别

    一.相同点: join()和get()方法都是用来获取CompletableFuture异步之后的返回值 二.区别: 1.join()方法抛出的是uncheck异常(即RuntimeException ...

  3. CompletableFuture详解~异常处理

    计算结果完成时的回调方法 当 CompletableFuture 的计算结果完成,或者抛出异常的时候,可以执行特定的 Action.主要是下面的方法: public CompletableFuture ...

  4. CompletableFuture详解~supplyAsync

    supplyAsync 可以支持返回值. //有返回值 public static void supplyAsync() throws Exception {CompletableFuture< ...

  5. CompletableFuture详解~allOf

    当所有的阶段都完成后创建一个阶段 上一个例子是当任意一个阶段完成后接着处理,接下来的两个例子演示当所有的阶段完成后才继续处理, 同步地方式和异步地方式两种. static void allOfExam ...

  6. CompletableFuture详解~anyOf

    当几个阶段中的一个完成,创建一个完成的阶段 下面的例子演示了当任意一个CompletableFuture完成后, 创建一个完成的CompletableFuture. 待处理的阶段首先创建, 每个阶段都 ...

  7. CompletableFuture详解~thenCompose

    组合 CompletableFuture 我们可以使用thenCompose()完成上面两个例子.这个方法等待第一个阶段的完成(大写转换), 它的结果传给一个指定的返回CompletableFutur ...

  8. CompletableFuture详解~thenCombine

    使用BiFunction处理两个阶段的结果 如果CompletableFuture依赖两个前面阶段的结果, 它复合两个阶段的结果再返回一个结果,我们就可以使用thenCombine()函数.整个流水线 ...

  9. CompletableFuture详解~thenAcceptBoth

    使用BiConsumer处理两个阶段的结果 上面的例子还可以通过BiConsumer来实现: static void thenAcceptBothExample() {String original ...

  10. CompletableFuture详解~runAfterBoth

    这个例子演示了依赖的CompletableFuture如果等待两个阶段完成后执行了一个Runnable.注意下面所有的阶段都是同步执行的,第一个阶段执行大写转换,第二个阶段执行小写转换 static ...

最新文章

  1. oracle中 怎么替换,oracle如何替换字符串?
  2. 学java时的一些笔记(2)
  3. 35个设计一流的美味的水果壁纸欣赏
  4. JavaScript创建Map对象(转)
  5. jenkins 使用LDAP认证
  6. chi660e电化学工作站软件_RuddlesdenPopper 型锰酸盐LaSr2Mn2O7的氧还原性能和作为电化学电容器电极材料的性能研究...
  7. python接口开发django_用 Django 开发接口
  8. 获取系统信息1——linux系统中的时间
  9. 漫步最优化十三——驻点
  10. 安卓系统怎么安装软件_「软件」怎么在虚拟机里安装系统
  11. 十、Axis WebService常用命令和调试工具
  12. php查询过滤字段,php 字符过滤类,用于过滤各类用户输入的数据
  13. java用jaxb三步解析xml_三步解决JAXB生成XML包含CDATA问题
  14. 哔哩哔哩下载视频,教程,下载b站视频来就对了,下载b站 视频电脑 pc端
  15. FPS类游戏的逆向分析通用方法与C++逆向功能开发详解
  16. Cyberspace_Security_Learning
  17. fetch请求cookie设置
  18. Mysql数据库——DQL数据查询语言
  19. 如何设计低功耗SOC
  20. 基于PX4六旋翼无人机百米悬停定点降落

热门文章

  1. 程序员求助:腾讯面试题,64匹马8个跑道,多少轮选出最快的四匹
  2. 小程序开发好学吗?需要掌握哪些知识技能?
  3. B - C语言实验——整数位
  4. 用qpst修复手机服务器禁用,QPST工具包没有qfil怎么办?
  5. 对计算机辅助英语的看法,论我国计算机辅助英语笔译的必要性
  6. Centos7.5 安装 mysql 5.7 ( 卸载自带 MariaDB)(实测)
  7. (二)使用预定义模型 QStringListModel例子
  8. 【转载】QT 的信号与槽机制介绍
  9. Python基础----集合
  10. CECC2018赛季收官站我国×××手夺得年度总冠军