我有以下代码:
public void restart() throws Exception
{
CompletableFuture<?> delayed = new CompletableFuture<>();
ScheduledExecutorService executorService =
Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(() ->
{
try
{
throw new RuntimeException("My exception.");
}
catch(Exception e)
{
delayed.completeExceptionally(e);
}
}, 1000L, 150L, TimeUnit.MILLISECONDS));
delayed.whenCompleteAsync((r, t) -> {
if (t != null)
{
throw new RuntimeException(t);
}
});
}
我正试图冒出我将在我的
executorService
中捕获的异常。但是相反发生的是在 try 块中抛出异常,该异常被捕获并且 CompletableFuture
是 completedExceptionally
。然后重新抛出异常。我希望通过这种方式我能够冒出异常。
但不幸的是,事实并非如此。
delayed
抛出异常但它不会冒泡。最重要的是,由于某种原因,异常循环在此之后立即开始。这是 try 不断抛出异常而 catch 不断捕获但是当然completableFuture
已经完成所以它不会到那个。
问题是我们如何处理和冒泡异常?
这对我有用:
public void restart() throws Exception {
CompletableFuture<?> delayed = new CompletableFuture<>();
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(() -> {
try {
throw new RuntimeException("My exception.");
} catch(Exception e) {
delayed.completeExceptionally(e);
}
}, 1000L, 150L, TimeUnit.MILLISECONDS);
try {
delayed.get();
} catch (ExecutionException e) {
throw (Exception) e.getCause();
}
}
在此修改后的代码中,我们在延迟的
get()
上调用 CompletableFuture
方法,该方法将阻塞直到 CompletableFuture
完成。如果 CompletableFuture
异常完成,get()
将抛出一个 ExecutionException
并以原始异常为原因。然后我们提取原因并将其作为Exception
重新抛出。这样,异常就会冒泡到 restart()
方法,并且可以得到适当的处理。
但是如果我们想在不使用阻塞 get 调用的情况下实现它,我们可以使用回调
Consumer<Throwable> callback
如果异常抛出,使用 callback.accept(e);
就像在这个片段中:
public static void main(String[] args) {
restart((t) -> System.out.println("Exception occurred: " + t.getMessage()));
}
public static void restart(Consumer<Throwable> callback) {
CompletableFuture.runAsync(() -> {
try {
// Code that may throw an exception goes here
throw new RuntimeException("My exception.");
} catch (Exception e) {
callback.accept(e);
}
});
}