CompletableFuture 详解

本文转载自: https://blog.csdn.net/mrxiky/article/details/78962614

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

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

进行变换
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表示起来会更加优雅。它的入参是上一个阶段计算后的结果,返回值是经过转化后结果。
例如:

    @Test
    public void thenApply() {
        String result = CompletableFuture.supplyAsync(() -> "hello").thenApply(s -> s + " world").join();
        System.out.println(result);
    }
结果为:

hello world
进行消耗
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
对上一步的计算结果不关心,执行下一个操作。
public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
thenRun它的入参是一个Runnable的实例,表示当得到上一步的结果时的操作。
例如:

    @Test
    public 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也要返回值之后,利用这两个返回值,进行转换后返回指定类型的值。
例如:

    @Test
    public 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
结合两个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也要返回值之后,利用这两个返回值,进行消耗。
例如:

    @Test
    public 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
在两个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)。
例如:

    @Test
    public 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);
我们现实开发场景中,总会碰到有两种渠道完成同一个事情,所以就可以调用这个方法,找一个最快的结果进行处理。
例如:

    @Test
    public 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
两个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);
例如:

    @Test
    public 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
两个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);
例如:

    @Test
    public 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
当运行时出现了异常,可以通过exceptionally进行补偿。
public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn);
例如:

    @Test
    public 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
当运行完成时,对结果的记录。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。这里为什么要说成记录,因为这几个方法都会返回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);
例如:

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

运行完成时,对结果的处理。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。
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使用起来还是比较爽的,看起来也比较优雅一点。

  

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

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

  1. 进行变换
  1.  
    public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
  2.  
    public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);
  3.  
    public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
  4.  
     

首先说明一下已Async结尾的方法都是可以异步执行的,如果指定了线程池,会在指定的线程池中执行,如果没有指定,默认会在ForkJoinPool.commonPool()中执行,下文中将会有好多类似的,都不详细解释了。关键的入参只有一个Function,它是函数式接口,所以使用Lambda表示起来会更加优雅。它的入参是上一个阶段计算后的结果,返回值是经过转化后结果。
例如:

  1.  
    @Test
  2.  
    publicvoidthenApply(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> "hello").thenApply(s -> s + " world").join();
  4.  
    System.out.println(result);
  5.  
    }
  6.  
     

结果为:

hello world
  1. 进行消耗
  1.  
    public CompletionStage<Void> thenAccept(Consumer<? super T> action);
  2.  
    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
  3.  
    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);
  4.  
     

thenAccept是针对结果进行消耗,因为他的入参是Consumer,有入参无返回值。
例如:

  1.  
    @Test
  2.  
    publicvoidthenAccept(){
  3.  
    CompletableFuture.supplyAsync(() -> "hello").thenAccept(s -> System.out.println(s+" world"));
  4.  
    }
  5.  
     

结果为:

hello world
  1. 对上一步的计算结果不关心,执行下一个操作。
  1.  
    public CompletionStage<Void> thenRun(Runnable action);
  2.  
    public CompletionStage<Void> thenRunAsync(Runnable action);
  3.  
    public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
  4.  
     

thenRun它的入参是一个Runnable的实例,表示当得到上一步的结果时的操作。
例如:

  1.  
    @Test
  2.  
    publicvoidthenRun(){
  3.  
    CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(2000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "hello";
  10.  
    }).thenRun(() -> System.out.println("hello world"));
  11.  
    while (true){}
  12.  
    }
  13.  
     

结果为:

hello world

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

  1.  
    public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
  2.  
    public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
  3.  
    public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
  4.  
     

它需要原来的处理返回值,并且other代表的CompletionStage也要返回值之后,利用这两个返回值,进行转换后返回指定类型的值。
例如:

  1.  
    @Test
  2.  
    publicvoidthenCombine(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(2000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "hello";
  10.  
    }).thenCombine(CompletableFuture.supplyAsync(() -> {
  11.  
    try {
  12.  
    Thread.sleep(3000);
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    return "world";
  17.  
    }), (s1, s2) -> s1 + " " + s2).join();
  18.  
    System.out.println(result);
  19.  
    }
  20.  
     

结果为:

hello world
  1. 结合两个CompletionStage的结果,进行消耗
  1.  
    public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
  2.  
    public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
  3.  
    public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);
  4.  
     

它需要原来的处理返回值,并且other代表的CompletionStage也要返回值之后,利用这两个返回值,进行消耗。
例如:

  1.  
    @Test
  2.  
    publicvoidthenAcceptBoth(){
  3.  
    CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(2000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "hello";
  10.  
    }).thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
  11.  
    try {
  12.  
    Thread.sleep(3000);
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    return "world";
  17.  
    }), (s1, s2) -> System.out.println(s1 + " " + s2));
  18.  
    while (true){}
  19.  
    }
  20.  
     

结果为:

hello world
  1. 在两个CompletionStage都运行完执行。
  1.  
    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
  2.  
    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
  3.  
    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor);
  4.  
     

不关心这两个CompletionStage的结果,只关心这两个CompletionStage执行完毕,之后在进行操作(Runnable)。
例如:

  1.  
    @Test
  2.  
    publicvoidrunAfterBoth(){
  3.  
    CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(2000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "s1";
  10.  
    }).runAfterBothAsync(CompletableFuture.supplyAsync(() -> {
  11.  
    try {
  12.  
    Thread.sleep(3000);
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    return "s2";
  17.  
    }), () -> System.out.println("hello world"));
  18.  
    while (true){}
  19.  
    }
  20.  
     

结果为

hello world

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

  1.  
    public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? superT, U> fn);
  2.  
    public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? superT, U> fn);
  3.  
    public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? superT, U> fn,Executorexecutor);
  4.  
     

我们现实开发场景中,总会碰到有两种渠道完成同一个事情,所以就可以调用这个方法,找一个最快的结果进行处理。
例如:

  1.  
    @Test
  2.  
    publicvoidapplyToEither(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "s1";
  10.  
    }).applyToEither(CompletableFuture.supplyAsync(() -> {
  11.  
    try {
  12.  
    Thread.sleep(2000);
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    return "hello world";
  17.  
    }), s -> s).join();
  18.  
    System.out.println(result);
  19.  
    }
  20.  
     

结果为:

hello world
  1. 两个CompletionStage,谁计算的快,我就用那个CompletionStage的结果进行下一步的消耗操作。
  1.  
    public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
  2.  
    public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
  3.  
    public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor);
  4.  
     

例如:

  1.  
    @Test
  2.  
    publicvoidacceptEither(){
  3.  
    CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "s1";
  10.  
    }).acceptEither(CompletableFuture.supplyAsync(() -> {
  11.  
    try {
  12.  
    Thread.sleep(2000);
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    return "hello world";
  17.  
    }), System.out::println);
  18.  
    while (true){}
  19.  
    }
  20.  
     

结果为:

hello world
  1. 两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)。
  1.  
    public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
  2.  
    public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
  3.  
    public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
  4.  
     

例如:

  1.  
    @Test
  2.  
    publicvoidrunAfterEither(){
  3.  
    CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "s1";
  10.  
    }).runAfterEither(CompletableFuture.supplyAsync(() -> {
  11.  
    try {
  12.  
    Thread.sleep(2000);
  13.  
    } catch (InterruptedException e) {
  14.  
    e.printStackTrace();
  15.  
    }
  16.  
    return "s2";
  17.  
    }), () -> System.out.println("hello world"));
  18.  
    while (true) {
  19.  
    }
  20.  
    }
  21.  
     

结果为:

hello world
  1. 当运行时出现了异常,可以通过exceptionally进行补偿。
  1.  
    public CompletionStage<T> exceptionally(Function<Throwable, ? extendsT> fn);
  2.  
     

例如:

  1.  
    @Test
  2.  
    publicvoidexceptionally(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    if (1 == 1) {
  10.  
    throw new RuntimeException("测试一下异常情况");
  11.  
    }
  12.  
    return "s1";
  13.  
    }).exceptionally(e -> {
  14.  
    System.out.println(e.getMessage());
  15.  
    return "hello world";
  16.  
    }).join();
  17.  
    System.out.println(result);
  18.  
    }
  19.  
     

结果为:

  1.  
    java.lang.RuntimeException: 测试一下异常情况
  2.  
    hello world
  3.  
     
  1. 当运行完成时,对结果的记录。这里的完成时有两种情况,一种是正常执行,返回值。另外一种是遇到异常抛出造成程序的中断。这里为什么要说成记录,因为这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常。所以不会对结果产生任何的作用。
  1.  
    public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
  2.  
    public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
  3.  
    public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,Executor executor);
  4.  
     

例如:

  1.  
    @Test
  2.  
    publicvoidwhenComplete(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    if (1 == 1) {
  10.  
    throw new RuntimeException("测试一下异常情况");
  11.  
    }
  12.  
    return "s1";
  13.  
    }).whenComplete((s, t) -> {
  14.  
    System.out.println(s);
  15.  
    System.out.println(t.getMessage());
  16.  
    }).exceptionally(e -> {
  17.  
    System.out.println(e.getMessage());
  18.  
    return "hello world";
  19.  
    }).join();
  20.  
    System.out.println(result);
  21.  
    }
  22.  
     

结果为:

  1.  
    null
  2.  
    java.lang.RuntimeException: 测试一下异常情况
  3.  
    java.lang.RuntimeException: 测试一下异常情况
  4.  
    hello world
  5.  
     

这里也可以看出,如果使用了exceptionally,就会对最终的结果产生影响,它没有口子返回如果没有异常时的正确的值,这也就引出下面我们要介绍的handle。

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

例如:
出现异常时

  1.  
    @Test
  2.  
    publicvoidhandle(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    //出现异常
  10.  
    if (1 == 1) {
  11.  
    throw new RuntimeException("测试一下异常情况");
  12.  
    }
  13.  
    return "s1";
  14.  
    }).handle((s, t) -> {
  15.  
    if (t != null) {
  16.  
    return "hello world";
  17.  
    }
  18.  
    return s;
  19.  
    }).join();
  20.  
    System.out.println(result);
  21.  
    }
  22.  
     

结果为:

hello world

未出现异常时

  1.  
    @Test
  2.  
    publicvoidhandle(){
  3.  
    String result = CompletableFuture.supplyAsync(() -> {
  4.  
    try {
  5.  
    Thread.sleep(3000);
  6.  
    } catch (InterruptedException e) {
  7.  
    e.printStackTrace();
  8.  
    }
  9.  
    return "s1";
  10.  
    }).handle((s, t) -> {
  11.  
    if (t != null) {
  12.  
    return "hello world";
  13.  
    }
  14.  
    return s;
  15.  
    }).join();
  16.  
    System.out.println(result);
  17.  
    }
  18.  
     

结果为:

s1

上面就是CompletionStage接口中方法的使用实例,CompletableFuture同样也同样实现了Future,所以也同样可以使用get进行阻塞获取值,总的来说,CompletableFuture使用起来还是比较爽的,看起来也比较优雅一点。

posted @ 2019-04-18 16:15  looyee  阅读(2450)  评论(0编辑  收藏  举报