简体   繁体   English

使用CompletableFuture抛出检查异常

[英]Throwing checked exceptions with CompletableFuture

Stackoverflow contains multiple questions about mixing checked exceptions with CompletableFuture . Stackoverflow包含多个有关将检查的异常与CompletableFuture混合的问题。

Here are a few examples: 这里有一些例子:

While some of answers hint at the use of CompletableFuture.completeExceptionally() their approach results in user code that is difficult to read. 尽管某些答案暗示使用CompletableFuture.completeExceptionally()它们的方法导致用户代码难以阅读。

I will use this space to provide an alternate solution that results in improved readability. 我将使用此空间来提供可提高可读性的替代解决方案。

Please note that this question is specific to CompletableFuture. 请注意,此问题特定于CompletableFuture。 This allows us to provide solutions that do not extend to lambda expressions more generally. 这使我们能够提供更广泛地不扩展到lambda表达式的解决方案。

Given the Completions utility class (provided below) users can throw checked exceptions seamlessly: 给定Completions实用程序类(下面提供),用户可以无缝地抛出检查的异常:

public CompletionStage<String> readLine()
{
  return Completions.supplyAsync(() ->
  {
    try (BufferedReader br = new BufferedReader(new FileReader("test.txt")))
    {
      return br.readLine();
    }
  });
}

Any exceptions thrown by the lambda (checked or not) will be wrapped in a CompletionException , which is consistent with CompletableFuture 's behavior for unchecked exceptions. 由lambda引发的任何异常(是否经过检查)都将包装在CompletionException ,这与CompletableFuture对于未检查的异常的行为一致。

Things get a bit uglier for intermediate steps like thenApply() but it's not the end of the world: 对于诸如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;
    }));
}

Here some methods from the Completions utility class. 这里有一些来自Completions实用工具类的方法。 You can wrap other CompletableFuture methods this way. 您可以通过这种方式包装其他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()
    {}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM