使用 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: "+divide(6,3).get()); System.out.println("exception: "+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: "+ex.getMessage()); } }); } try { System.out.println("success: "+whenComplete(6,3).get()); System.out.println("exception: "+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: "+ex.getMessage()); return 0; }); } try { System.out.println("success: "+FutureTest.exceptionally(6,3).get()); System.out.println("exception: "+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()方法,它可以从异常中恢复过来。