如何包装已检查的异常,但保留Java中的原始运行时异常

如何包装已检查的异常,但保留Java中的原始运行时异常,java,runtimeexception,checked-exceptions,Java,Runtimeexception,Checked Exceptions,我有一些代码可能会抛出检查异常和运行时异常 try { // some code that can throw both checked and runtime exception } catch (Exception e) { throw rethrow(e); } 我希望捕获选中的异常并用运行时异常包装它。但是如果抛出RuntimeException,我不必包装它,因为它已经是运行时异常了 我的解决方案有点开销,不“整洁”: 有更优雅的方式吗?没有 如果你经常这样做,你可以把它塞

我有一些代码可能会抛出检查异常和运行时异常

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
  throw rethrow(e);
}
我希望捕获选中的异常并用运行时异常包装它。但是如果抛出RuntimeException,我不必包装它,因为它已经是运行时异常了

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

有更优雅的方式吗?没有

如果你经常这样做,你可以把它塞进一个helper方法中

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);
}
我使用“盲”重播来传递已检查的异常。我已经使用它来传递Streams API,在这里我不能使用lambdas来抛出已检查的异常。e、 g我们有XXXXX功能接口,因此可以通过检查异常

这使我能够自然地捕获调用方中的已检查异常,而无需知道被调用方必须通过不允许已检查异常的接口来传递它

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
  throw rethrow(e);
}
在调用方法中,我可以再次声明选中的异常

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

/**
*将CheckedException强制转换为未经检查的异常。
*
*@param可抛投
*@param可丢弃的类型
*@return此方法不会返回可丢弃的实例,只会将其抛出。
*@将可丢弃的东西作为未经检查的可丢弃的东西扔掉
*/
@抑制警告(“未选中”)
公共静态运行时异常重试(Throwable Throwable)抛出{
扔(T)可扔;//依靠真空浇铸
}
处理异常有很多不同的选项。我们使用其中的一些


您可以使用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);
    }
}
不过,您的解决方案看起来更好。

番石榴的做法正是:

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

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

问题在于
异常范围太广。您应该确切地知道可能的检查异常是什么

try {
    // code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
    throw new RuntimeException(ex);
}
这不起作用的原因揭示了应该解决的更深层次的问题:

如果一个方法声明它
抛出异常
,那么它太宽了。没有进一步的信息就知道“可能会出问题”,对打电话的人来说是没有用的。该方法应该在有意义的层次结构中使用特定的异常类,或者在适当的情况下使用未检查的异常

如果一个方法抛出太多不同类型的checked异常,那么它就太复杂了。它要么被重构成多个更简单的方法,要么根据情况将异常安排在合理的继承层次结构中


当然,这条规则也可能有例外。如果一个方法被某种横切框架(如JUnit、AspectJ或Spring)使用,而不是包含供其他人使用的API,那么声明一个方法抛出异常是完全合理的。

我通常使用相同类型的代码结构,但将其压缩为一行,这是三元运算符实际上使代码变得更好的为数不多的几次之一:

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

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

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

public class Thrower {
    public static void Throw(java.lang.Throwable t) {
        throw t;
    }
}
它只是工作。java编译器通常会拒绝编译,但字节码验证器根本不在乎

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

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
    Thrower.Throw(e);
}

就这样。唯一的改进是一个高阶函数,它接受lambda,lambda是
try
主体,并用此逻辑对其进行包装。您可以查看此主题:我相信这是一种更优雅的方法。因此,这实际上在运行时抛出IOException(来自
rethrow
),但编译器认为这是一个未经检查的异常(因为您说过您将以这种方式进行强制转换,即使强制转换已被擦除)?@Thilo在运行时,JVM的检查和取消检查之间没有区别,有几种方法可以“愚弄”在运行时工作的编译器。使用泛型的演员阵容是我觉得最简单的。我喜欢。:-)(是的,没有lamdbas的例外是不方便的。)“鬼鬼祟祟”是这个的半官方名称:)@AlikElzin kilaka是的,这个语法只适用于Java8中的新推理规则。Java7需要一个包含两个方法的较长的习惯用法。您是如何编译它的?我编辑了javac源代码以完成检查,编译了javac,并使用该javac编译.class文件。生成的.class文件可以被普通的javac.Wow编译的.java编译器引用,这不是我所期望的。文件在什么地方可以找到吗?这是说明。我不确定,但我认为博客海报是从我在sun的旧java bug存储库中的原始说明中获得的。如果bug存储库仍然存在,那么.class文件就在那里。甚至比Peter的答案还要狡猾。我喜欢。将
catch(异常e)
更改为
catch(Throwable e)
?@JasonS:如果您还想捕获
错误(不推荐这样做),您可以这样做。我只会让这些事情不受影响。编译器不会对此抱怨的。我想重点是没有理由使用
Throwable
,如果您只捕获
异常
@OrangeDog,那么
错误
就有一个特例,可能耦合太低了,是的。该方法的适用范围比调用该方法的示例代码所需的范围更广。但对于许多异常处理实用程序来说也是如此,例如前面提到的Guava
Throwables.propagate
或Peter的
rethrow
。他的方法不是声明它抛出异常,而是希望优雅地捕获调用堆栈下的某个对象是否抛出异常,这可能包括由他直接调用的方法声明的任何类型化异常,或任何其他类似NPE或任何可能出错的东西。完全合理。@user467257是的,我理解操作。我指出我建议的模式不起作用
try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
    Thrower.Throw(e);
}