完成计算异常
现在我们来看一下异步操作如何显式地返回异常,用来指示计算失败。我们简化这个例子,操作处理一个字符串,把它转换成答谢,我们模拟延迟一秒。
我们使用thenApplyAsync(Function, Executor)
方法,第一个参数传入大写函数, executor是一个delayed executor,在执行前会延迟一秒。
static void completeExceptionallyExample() {
CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase,
CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));
CompletableFuture exceptionHandler =
cf.handle((s, th) -> { return (th != null) ? "message upon cancel" : ""; });
cf.completeExceptionally(new RuntimeException("completed exceptionally"));
assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally());
try {
cf.join();
fail("Should have thrown an exception");
} catch(CompletionException ex) { // just for testing
assertEquals("completed exceptionally", ex.getCause().getMessage());
}
assertEquals("message upon cancel", exceptionHandler.join());
}
让我们看一下细节。
首先我们创建了一个CompletableFuture, 完成后返回一个字符串message
,接着我们调用thenApplyAsync
方法,它返回一个CompletableFuture。这个方法在第一个函数完成后,异步地应用转大写字母函数。
这个例子还演示了如何通过delayedExecutor(timeout, timeUnit)
延迟执行一个异步任务。
我们创建了一个分离的handler
阶段:exceptionHandler, 它处理异常异常,在异常情况下返回message upon cancel
。
下一步我们显式地用异常完成第二个阶段。在阶段上调用join
方法,它会执行大写转换,然后抛出CompletionException(正常的join会等待1秒,然后得到大写的字符串。不过我们的例子还没等它执行就完成了异常), 然后它触发了handler阶段。