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使用起來還是比較爽的,看起來也比較優雅一點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM