有些人试图说服你必须遵守规则。听着,但你是否服从,你应该根据你的情况自己决定。现实是“你应该遵守规则”(而不是“你必须遵守规则”)。请注意,如果您不遵守规则,可能会产生后果。
这种情况不仅适用于 .java 的情况Runnable
,而且在 Java 8 的情况下也非常频繁地出现在 Streams 和其他引入了功能接口而无法处理已检查异常的地方的上下文中。例如,、 、Consumer
等等Supplier
都被声明为没有处理检查异常的设施。Function
BiFunction
那么有哪些情况和选择呢?在下面的文本中,Runnable
代表任何不声明异常或声明的异常对于手头的用例来说过于有限的功能接口。
- 你已经在
Runnable
某个地方声明了自己,并且可以Runnable
用其他东西代替。
- 考虑替换
Runnable
为Callable<Void>
. 基本相同,但允许抛出异常;最后必须这样做return null
,这是一个轻微的烦恼。
- 考虑用
Runnable
您自己的自定义替换,该自定义@FunctionalInterface
可以准确地抛出您想要的那些异常。
- 您已经使用了 API,并且可以使用替代方法。例如,某些 Java API 是重载的,因此您可以
Callable<Void>
使用Runnable
.
- 您已经使用了 API,并且没有其他选择。在这种情况下,您仍然没有选择余地。
- 您可以将异常包装在
RuntimeException
.
- 您可以使用未经检查的强制转换将异常破解为 RuntimeException。
您可以尝试以下方法。这有点像 hack,但有时我们需要 hack。因为,一个异常应该被检查还是不被检查是由它的类型定义的,但实际上应该由情况来定义。
@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
@Override
default void run() {
try {
tryRun();
} catch (final Throwable t) {
throwUnchecked(t);
}
}
private static <E extends RuntimeException> void throwUnchecked(Throwable t) {
throw (E) t;
}
void tryRun() throws Throwable;
}
我更喜欢这个,new RuntimeException(t)
因为它的堆栈跟踪更短。
您现在可以执行以下操作:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
免责声明:以这种方式执行未经检查的强制转换的能力实际上可能在 Java 的未来版本中被删除,因为泛型类型信息不仅在编译时处理,而且在运行时处理。