如何包装已检查的exception但在Java中保留原始运行时exception

我有一些代码可能会抛出已检查和运行时exception。

我想捕获已检查的exception并将其包装为运行时exception。 但是如果抛出RuntimeException,我不必包装它,因为它已经是运行时exception。

我的解决方案有点开销,并不“整洁”:

try { // some code that can throw both checked and runtime exception } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } 

想要更优雅的方式吗?

我使用“盲目”重新抛出来传递已检查的exception。 我已经使用它来传递Streams API,我不能使用抛出已检查exception的lambdas。 例如,我们有ThrowingXxxxxfunction接​​口,因此可以传递经过检查的exception。

这允许我自然地在调用者中捕获已检查的exception,而不需要知道被调用者必须通过不允许检查exception的接口传递它。

 try { // some code that can throw both checked and runtime exception } catch (Exception e) { throw rethrow(e); } 

在调用方法中,我可以再次声明已检查的exception。

 public void loadFile(String file) throws IOException { // call method with rethrow } 

 /** * Cast a CheckedException as an unchecked one. * * @param throwable to cast * @param  the type of the Throwable * @return this method will never return a Throwable instance, it will just throw it. * @throws T the throwable as an unchecked throwable */ @SuppressWarnings("unchecked") public static  RuntimeException rethrow(Throwable throwable) throws T { throw (T) throwable; // rely on vacuous cast } 

处理exception有很多不同的选择。 我们使用其中的一些。

https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html

Guava的Throwables.propagate()这样做的:

 try { // some code that can throw both checked and runtime exception } catch (Exception e) { throw Throwables.propagate(e); } 

更新:此方法现已弃用。 有关详细说明,请参阅此页面 。

并不是的。

如果你经常这么做,你可以把它塞进一个辅助方法。

 static RuntimeException unchecked(Throwable t){ if (t instanceof RuntimeException){ return (RuntimeException) t; } else if (t instanceof Error) { // if you don't want to wrap those throw (Error) t; } else { return new RuntimeException(t); } } try{ // .. } catch (Exception e){ throw unchecked(e); } 

我有一个特殊编译的.class文件,其中包含以下内容:

 public class Thrower { public static void Throw(java.lang.Throwable t) { throw t; } } 

它只是有效。 java编译器通常会拒绝编译它,但字节码validation器根本不关心。

该课程的使用类似于Peter Lawrey的答案:

 try { // some code that can throw both checked and runtime exception } catch (Exception e) { Thrower.Throw(e); } 

您可以使用instanceof运算符重写相同的内容

 try { // some code that can throw both checked and runtime exception } catch (Exception e) { if (e instanceof RuntimeException) { throw e; } else { throw new RuntimeException(e); } } 

但是,您的解决方案看起来更好

问题是Exception太宽泛了。 您应该确切知道可能的已检查exception是什么。

 try { // code that throws checked and unchecked exceptions } catch (IOException | SomeOtherException ex) { throw new RuntimeException(ex); } 

这不起作用的原因揭示了应该解决的更深层次的问题:

如果一个方法声明它throws Exception那么它太宽泛了。 在没有进一步信息的情况下知道“出现问题”对于呼叫者来说是没用的。 该方法应该在有意义的层次结构中使用特定的exception类,或者在适当的情况下使用未经检查的exception。

如果一个方法抛出太多不同类型的已检查exception,那么它太复杂了。 它应该被重构为多个更简单的方法,或者exception应该根据情况安排在合理的inheritance层次结构中。

当然,规则可能有例外。 声明一个方法throws Exception如果它被某种交叉框架(例如JUnit或AspectJ或Spring)使用而不是包含供其他人使用的API,那么它是完全合理的。

我通常使用相同类型的代码结构,但是在三元运算符实际使代码更好的几次中将其压缩到一行:

 try { // code that can throw } catch (Exception e) { throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e); } 

这不需要额外的方法或catch块,这就是我喜欢它的原因。