使用 CompletableFuture 編寫代碼時,異常處理很重要。
CompletableFuture 提供了三種方法來處理它們:handle()、whenComplete() 和 exceptionly()。
handle() | whenComplete() | exceptionly() | |
訪問成功 | Yes | Yes | No |
訪問失敗 | Yes | Yes | Yes |
能從失敗中恢復 | Yes | No | Yes |
能轉換結果從T 到 U | Yes | No | No |
成功時觸發 | Yes | Yes | No |
失敗時觸發 | Yes | Yes | Yes |
有異步版本 | Yes | Yes | Yes(12版本) |
1、handle()
public <U> CompletableFuture<U> handle(java.util.function.BiFunction<? super T, Throwable, ? extends U> fn)
返回一個新的 CompletionStage階段,當此階段正常或異常完成時,將使用此階段的結果和異常作為所提供函數的參數來執行。
當此階段完成時,以該階段的結果(如果沒有則為null)和該階段的異常(如果沒有則為null)作為參數調用給定函數,並且函數的結果用於完成返回的階段
不會把異常外拋出來。
public static CompletableFuture divide(int a, int b){ return CompletableFuture.supplyAsync(() -> a/b) .handle((result, ex) -> { if (null != ex) { System.out.println(ex.getMessage()); return 0; } else { return result; } }); } try { System.out.println("success:\t"+divide(6,3).get()); System.out.println("exception:\t"+divide(6,0).get()); } catch (Exception exception){ System.out.println("catch="+exception.getMessage()); } 輸出結果: success: 2 java.lang.ArithmeticException: / by zero exception: 0
2、whenComplete()
public CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T, ? super Throwable> action)
可以訪問當前completable future的結果和異常作為參數:使用它們並執行您想要的操作。
此方法並不能轉換完成的結果。會內部拋出異常。
public static CompletableFuture whenComplete(int a, int b){ return CompletableFuture.supplyAsync(() -> a/b) .whenComplete((result, ex) -> { if (null != ex) { System.out.println("whenComplete error:\t"+ex.getMessage()); } }); } try { System.out.println("success:\t"+whenComplete(6,3).get()); System.out.println("exception:\t"+whenComplete(6,0).get()); } catch (Exception exception){ System.out.println("catch===="+exception.getMessage()); } 輸出: success: 2 whenComplete error: java.lang.ArithmeticException: / by zero catch====java.lang.ArithmeticException: / by zero
3、exceptionly()
public CompletableFuture<T> exceptionally(java.util.function.Function<Throwable, ? extends T> fn)
該方法僅處理異常情況:發生異常時。
如果可完成的未來成功完成,那么“異常”內部的邏輯將被跳過。
不會把內部異常拋出來。
public static CompletableFuture exceptionally(int a, int b){ return CompletableFuture.supplyAsync(() -> a/b) .exceptionally(ex -> { System.out.println("ex:\t"+ex.getMessage()); return 0; }); } try { System.out.println("success:\t"+FutureTest.exceptionally(6,3).get()); System.out.println("exception:\t"+FutureTest.exceptionally(6,0).get()); } catch (Exception exception){ System.out.println("catch===="+exception.getMessage()); } 輸出: success: 2 ex: java.lang.ArithmeticException: / by zero exception: 0
如果只專注於異常處理,選擇exceptionally(),它可以簡化了輸入參數,並且可以避免異常空檢查的if語句。
如果希望不影響主流程,也不加try進行捕獲,使用handle()方法,它可以從異常中恢復過來。