终端操作(例如 forEach)可以重新抛出已检查的异常吗?

Posted

技术标签:

【中文标题】终端操作(例如 forEach)可以重新抛出已检查的异常吗?【英文标题】:Can a terminal operation (e.g. forEach) rethrow checked exceptions? 【发布时间】:2014-03-08 13:45:05 【问题描述】:

我有一个方法可以删除一些文件:

void deepDelete(Path root) 
    Files.walk(root)
            .filter(p -> !Files.isDirectory(p))
            .forEach(p ->  try  Files.delete(p); 
                            catch (IOException e)  /* LOG */ 
            );

try/catch 块会降低操作的可读性,尤其是与使用方法引用相比:

void deepDelete(Path root) throws IOException 
    Files.walk(root)
            .filter(p -> !Files.isDirectory(p))
            .forEach(Files::delete); //does not compile

很遗憾,该代码无法编译。

有没有办法应用在终端操作中引发检查异常并简单地“重新引发”任何异常的操作?

我知道我可以编写一个将已检查异常转换为未检查异常的包装器,但如果可能的话,我宁愿坚持使用 JDK 中的方法。

【问题讨论】:

显然,Java 8 远离了 checked 异常。几乎所有新引入的异常都是unchecked,而新引入的方法使用unchecked异常,例如Files.list 抛出 UncheckedIOException。 @nosid: 看不到已检查异常的总体趋势。只有 流操作 会抛出 UncheckedIOException,原因与此问题中讨论的相同:流 API 不允许抛出已检查的 IOException。如果IOException 在构造流之前发生,则通常会检查它。 【参考方案1】:

据我所知:没有。我使用this techempower article 作为我的 java8 指南,它非常明确(参见标题为“异常透明度”的部分)。

【讨论】:

【参考方案2】:

如果你声明这个方法:

@SuppressWarnings("unchecked")
static <T extends Throwable> RuntimeException sneakyThrow(Throwable t) throws T 
    throw (T)t;

那么你可以这样做:

try 
    Files.delete(p);
 catch (IOException e) 
    throw sneakyThrow(e);

这绕过检查的异常规则并抛出原始IOException 而不进行包装,尽管您仍然必须捕获它并重新抛出。我并不是说这是一个好主意,而是一个的主意。

【讨论】:

以上是关于终端操作(例如 forEach)可以重新抛出已检查的异常吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在这种情况下允许抛出已检查的异常类型?

AppDomain.UnhandledException 自动重新抛出已处理的异常

使用 Mockito 从模拟中抛出已检查的异常

Spring Security 部署失败:生命周期方法 [initialize] 不得抛出已检查异常

按钮操作块内的 Foreach 循环抛出“Type() 不能符合视图”

解决Eureka Server不踢出已关停的节点的问题