当前位置: 首页 > 面试题库 >

使用CompletableFuture抛出检查异常

经和洽
2023-03-14
问题内容

包含多个有关将检查的异常与混合使用的问题CompletableFuture

虽然一些答案暗示使用CompletableFuture.completeExceptionally()其方法会导致难以阅读的用户代码。

我将使用此空间来提供可提高可读性的替代解决方案

请注意,此问题特定于CompletableFuture。 这使我们能够提供更广泛地不扩展到lambda表达式的解决方案。


问题答案:

给定Completions实用程序类(下面提供),用户可以无缝地抛出检查异常:

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

由lambda引发的任何异常(是否经过检查)都将包装在中CompletionException,这与CompletableFuture的非检查异常行为相同。

对于诸如此类的中间步骤,事情会变得更糟,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()
    {}
}


 类似资料:
  • 假设我想在收到特定异常时恢复某个值,否则返回失败的未来。我希望是这样的: 如果函数会抛出检查过的异常,我想在链式方法中处理它。我尝试过和,但都无法编译。是否为这种情况提供了任何解决方案?我知道接口是方法的参数,它不会抛出任何异常——在这种情况下,我只想返回已经失败的未来。我想找到使用Java8的解决方案。

  • 问题内容: 我有以下代码: 抛出一个。我不想在这里处理此问题,但是将异常从抛出给的调用者。 问题答案: 您的代码建议您稍后以相同的方法使用异步操作的结果,因此无论如何都必须进行处理,因此一种处理方法是 在的异步处理中抛出的所有异常都将在调用时包装为一个,除了我们已经包装在一个。 当重新引发的原因时,我们可能会遇到未检查的异常,即or的子类或我们的自定义检查的异常。上面的代码通过多次捕获来处理所有这

  • 使用CompletableFuture这一伟大特性,我想将使用异常的旧异步代码转换为这一新特性。但检查的异常是困扰我的东西。这是我的代码。 方法的签名: 如何处理ComletableFuture中的检查异常?

  • 问题内容: 假设我开发了一个扩展,该扩展不允许测试方法名称以大写字符开头。 现在,我要测试我的扩展程序是否按预期工作。 如何编写测试以验证尝试执行第二种方法是否抛出带有特定消息的RuntimeException? 问题答案: 在尝试了答案中的解决方案和注释中链接的问题之后,我最终使用了JUnit Platform Launcher解决方案。 JUnit本身不会运行,因为它是不带的内部类。因此,在构

  • 如何从Java 8流/lambda内部抛出检查异常? 换句话说,我想让像这样的代码编译: 此代码未编译,因为上面的方法抛出了,而该方法已被选中。 请注意,我不想在运行时异常中包装已检查的异常,而抛出包装的未检查的异常。我想抛出检查的异常本身,并且不向流中添加丑陋的/。

  • 我试图在lambda内部抛出一个异常,但它总是给我一个错误,表示未处理的IOException。 有人能告诉我我做错了什么吗?