Java 使用CompletableFuture抛出已检查的异常
Stackoverflow包含多个关于将选中的异常与Java 使用CompletableFuture抛出已检查的异常,java,completable-future,Java,Completable Future,Stackoverflow包含多个关于将选中的异常与CompletableFuture混合的问题 以下是几个例子: 虽然一些答案暗示使用了CompletableFuture.completeeexceptionaly(),但他们的方法会导致用户代码难以阅读 我将使用此空间提供另一种解决方案,以提高可读性 请注意,此问题特定于CompletableFuture。这使我们能够提供不扩展到更一般的lambda表达式的解决方案。鉴于Completions实用程序类(如下提供),用户可以无缝抛出
CompletableFuture
混合的问题
以下是几个例子:
CompletableFuture.completeeexceptionaly()
,但他们的方法会导致用户代码难以阅读
我将使用此空间提供另一种解决方案,以提高可读性
请注意,此问题特定于CompletableFuture。这使我们能够提供不扩展到更一般的lambda表达式的解决方案。鉴于
Completions
实用程序类(如下提供),用户可以无缝抛出选中的异常:
public CompletionStage<String> readLine()
{
return Completions.supplyAsync(() ->
{
try (BufferedReader br = new BufferedReader(new FileReader("test.txt")))
{
return br.readLine();
}
});
}
下面是完成
实用程序类中的一些方法。您可以用这种方式包装其他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()
{}
}
/**
*{@code CompletionStage}的助手函数。
*
*@作者Gili Tzabari
*/
公开期末结业
{
/**
*返回一个{@code CompletionStage},该值以{@code CompletionStage}的值或异常完成
*由{@code callable}使用提供的{@code executor}返回。如果{@code callable}引发异常
*返回的{@code CompletionStage}已使用它完成。
*
*@param{@code callable}返回的值的类型
*@param callable返回一个值
*@param executor将运行{@code callable}的执行器
*@return由{@code callable}返回的值
*/
公共静态CompletionStage SupplySync(可调用、可调用、执行器-执行器)
{
返回CompletableFuture.SupplySync(()->wrapExceptions(可调用),executor);
}
/**
*用{@code CompletionException}包装或替换操作引发的异常。
*
*如果异常被设计为包装其他异常,例如{@code ExecutionException},则其根本原因被包装;否则
*顶级异常已包装。
*
*@param可调用函数返回的值的类型
*@param可调用返回值的操作
*@return可调用函数返回的值
*@throws CompletionException如果可调用的抛出任何异常
*/
公共静态T WrapeExceptions(可调用可调用)
{
尝试
{
返回callable.call();
}
捕获(完成异常e)
{
//避免包装
投掷e;
}
捕获(执行例外)
{
抛出新的CompletionException(例如getCause());
}
捕获(可丢弃的e)
{
抛出新的CompletionException(e);
}
}
/**
*返回一个{@code CompletionStage},该值以{@code CompletionStage}的值或异常完成
*{@code callable}使用默认执行器返回。如果{@code callable}引发异常,则返回
*{@code CompletionStage}已使用它完成。
*
*@param{@code callable}返回的值的类型
*@param callable返回一个值
*@return由{@code callable}返回的值
*/
公共静态CompletionStage SupplySync(可调用可调用)
{
返回CompletableFuture.SupplySync(()->wrapExceptions(可调用));
}
/**
*防止施工。
*/
私人完成()
{}
}
我不确定捕获所有可丢弃的类型并包装在CompletionException
中是否是一个好主意。特别是,我认为这对java.lang.Error
@msandiford尤其不利,如果深入研究CompletableFuture
实现,您将看到它们也会这样做(例如在uniApply()
方法中)。用户希望能够记录错误,比如AssertionError
,否则他们的代码会自动失败,他们不知道出了什么问题。也许我没有抓住你想说的要点,但是CompletableFuture
机器能处理这种情况吗?在什么情况下,AssertionError
(例如)会被吞没而不会在管道中的某个地方导致用户可见的ExecutionException
。@msandifordCompletableFuture
机器处理这种情况的原因是因为它捕获了可丢弃的。此包装器必须提供与底层实现相同的功能,并支持检查的异常。因此,如果底层实现捕获了可丢弃的
,那么包装器也必须捕获。
/**
* 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()
{}
}