我有以下代码:
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();
}
}
在这个修改后的代码中,我们在延迟的CompletableFuture
上调用get()
方法,该方法将阻塞直到CompletableFuture
完成。如果CompletableFuture
异常完成,则get()
抛出一个ExecutionException
,并将原始异常作为其原因。然后,我们提取原因并将其重新列为Exception
。通过这种方式,异常被冒泡到restart()
方法中,并且可以进行适当的处理。
但是,如果我们想在不使用阻塞get调用的情况下实现它,我们可以使用回调Consumer<Throwable> callback
,如果exeption抛出,则使用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);
}
});
}