Java中是否有标准的注释来指示nothrow语义?

12

我希望记录一下Java中的一个接口方法,该方法不允许传播异常,并且需要某种静态分析来验证实现该方法的类是否捕获并处理了可能传播到该方法的任何异常。可以使用@NoThrow之类的注释。

例如,我希望能够编写:

interface SomeServiceProviderInterface {
   @NoThrow
   @NonNull
   SomeResult someComputation();
}

...并且需要确保实现遵守此接口契约。是否已经存在一个注释和静态分析工具可以做到这一点?如果没有,是否有人知道是否可以通过注释处理器实现这一点(它能否看到代码中是否包含try...catch块?),或者对如何实现这样的工具有任何指导或建议?谢谢!


4
除了使用空的catch块或接近空的catch块通过捕获Throwable来实现此操作,我对此表示怀疑,因为在catch块中有任何重要代码都会创建对象,这可能导致抛出OutOfMemoryError。这样做也可能是错误的。某些throwable,例如错误对象和一些运行时异常对象,确实设计成永远不被捕获。 - Warren Dew
2
@WarrenDew 好的,为了论证,假设它实际上更像是 "@ThrowsOnly(Error.class)",其中像 "Error" (和OutOfMemoryError) 这样的严重错误可以被抛出,但我想保证子类不会传播类型 "Exception"... 你有什么想法吗?在这个特定的情况下,我真的想这样做。 - Michael Aaron Safyan
只需在函数签名中不指定throws子句,实现就不能抛出已检查异常。 - Warren Dew
除此之外,您可能可以编写一个注释来检查函数体并验证未构造任何异常,可能还要检查是否存在空指针异常的可能性,并检查所有调用的函数也具有相同的注释,从而递归地验证它们。我对其有疑问,因为您将无法使用任何库。也许更有用的是将接口更改为抽象类,并将整个函数体放入try/catch块中。 - Warren Dew
2
静态知识表明一个方法不会抛出异常,这非常有价值。它可以大大简化调用代码,并对异常处理策略产生影响。省略throws子句显然不是解决方案,因为它仍允许RuntimeException。我建议您看一下C++的noexcept关键字,这是对异常处理进行了十年研究的结论。虽然Java和C++之间存在语言差异,但其中许多C++的论点也适用于Java。甚至更多,因为Java的异常安全性,try-finally/try-with-resources,比RAII要弱得多。 - TheOperator
1
我认为正确的实现方式不是在运行时通过注释进行检查,而是使用表明您意图的注释,并使用静态分析工具验证该声明。就像Eclipse / IntelliJ中实现的@NonNull一样。 - Alexander Oh
2个回答

5

无法提供这样的注释,因为无法保证方法不会抛出异常。这是因为任何方法随时可能抛出VirtualMachineError。特别是,即使一个方法没有直接或间接地分配内存(使用new运算符),它仍然可能抛出OutOfMemoryError。这并不是一种单纯理论上的担忧:如果垃圾回收线程运行时间过长,某些并发垃圾回收器将执行此操作。


绝对可以有这样的注释。它的意思将类似于“不会发出 java.lang.Exception”。但是从实际意义上讲,这并不会降低其价值。 - Pavel Vlasov

1

不令人满意的答案

异常是一种有价值的语言元素,它们不仅允许您处理错误,还可以快速计算。想象一下,您正在搜索高度分支递归算法中最短的列表。当遇到空列表时,您可以通过抛出异常立即返回结果,表示找到了空列表。

当然,为了跳过不可行的计算而不是冒泡式地返回null,可以使用子例程。

因此,这个问题涉及到避免许多if语句以便于测试(否则未经测试的代码部分可能会被埋藏在代码的控制流中)。

为导入异常类和危险调用(Integer.parseInt)进行类扫描需要付出很大努力。其中一些,代码分析器已经发出警告。

我认为 try {...} catch (Throwable/RuntimeException e) {} 只是针对一些旧版本。在这种情况下,AOP也会有所帮助。

最佳替代方案是集成异常。有评估库(我不记得它们的名字 - 也许与continuations相关),可以处理异常并处理混合结果。有点像现在的Streams,其中异常部分异步处理等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接