包含多个有关将检查的异常与混合使用的问题CompletableFuture。
CompletableFuture
虽然一些答案暗示使用CompletableFuture.completeExceptionally()其方法会导致难以阅读的用户代码。
CompletableFuture.completeExceptionally()
我将使用此空间来提供可提高可读性的替代解决方案。
请注意,此问题特定于CompletableFuture。 这使我们能够提供更广泛地不扩展到lambda表达式的解决方案。
给定Completions实用程序类(下面提供),用户可以无缝地抛出检查异常:
Completions
public CompletionStage<String> readLine() { return Completions.supplyAsync(() -> { try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) { return br.readLine(); } }); }
由lambda引发的任何异常(是否经过检查)都将包装在中CompletionException,这与CompletableFuture的非检查异常行为相同。
CompletionException
对于诸如此类的中间步骤,事情会变得更糟,thenApply()但这还不是世界末日:
thenApply()
public CompletionStage<String> transformLine() { return readLine().thenApply(line -> Completions.wrapExceptions(() -> { if (line.contains("%")) throw new IOException("Lines may not contain '%': " + line); return "transformed: " + line; })); }
这里是Completions实用程序类的一些方法。您可以CompletableFuture通过这种方式包装其他方法。
/** * Helper functions for {@code CompletionStage}. * * @author Gili Tzabari */ public final class Completions { /** * Returns a {@code CompletionStage} that is completed with the value or exception of the {@code CompletionStage} * returned by {@code callable} using the supplied {@code executor}. If {@code callable} throws an exception the * returned {@code CompletionStage} is completed with it. * * @param <T> the type of value returned by {@code callable} * @param callable returns a value * @param executor the executor that will run {@code callable} * @return the value returned by {@code callable} */ public static <T> CompletionStage<T> supplyAsync(Callable<T> callable, Executor executor) { return CompletableFuture.supplyAsync(() -> wrapExceptions(callable), executor); } /** * Wraps or replaces exceptions thrown by an operation with {@code CompletionException}. * <p> * If the exception is designed to wrap other exceptions, such as {@code ExecutionException}, its underlying cause is wrapped; otherwise the * top-level exception is wrapped. * * @param <T> the type of value returned by the callable * @param callable an operation that returns a value * @return the value returned by the callable * @throws CompletionException if the callable throws any exceptions */ public static <T> T wrapExceptions(Callable<T> callable) { try { return callable.call(); } catch (CompletionException e) { // Avoid wrapping throw e; } catch (ExecutionException e) { throw new CompletionException(e.getCause()); } catch (Throwable e) { throw new CompletionException(e); } } /** * Returns a {@code CompletionStage} that is completed with the value or exception of the {@code CompletionStage} * returned by {@code callable} using the default executor. If {@code callable} throws an exception the returned * {@code CompletionStage} is completed with it. * * @param <T> the type of value returned by the {@code callable} * @param callable returns a value * @return the value returned by {@code callable} */ public static <T> CompletionStage<T> supplyAsync(Callable<T> callable) { return CompletableFuture.supplyAsync(() -> wrapExceptions(callable)); } /** * Prevent construction. */ private Completions() {} }