实用程序类重新抛出throwable为未选中状态?

bil*_*.cn 6 java exception utility-method

我在单元测试包装器方法中捕获所有throwable,以便重置外部系统中的一些数据.我想在完成后重新抛出原始异常并且我正在使用这段代码来执行此操作:

if (t instanceof RuntimeException) {
    throw (RuntimeException) t;
} else if (t instanceof Error) {
    throw (Error) t;
} else {
    throw new RuntimeException(t);
}
Run Code Online (Sandbox Code Playgroud)

但是,是否有任何现有的实用程序调用已经执行此操作?

(我正在捕捉throwables因为AssertionErrors是错误.)

编辑:说实话,我真的不想包装异常,所以任何允许我抛出任何throwable(包括检查异常)而不声明抛出的技巧都是可以接受的.

Mar*_*nik 10

是的,有一种方法可以编写一个方法来避免包装已检查的异常.对于这个用例,它是一个完美的匹配,虽然你应该非常小心它,因为它很容易混淆不熟悉的.这里是:

@SuppressWarnings("unchecked")
public static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
    throw (T) t;
}
Run Code Online (Sandbox Code Playgroud)

你会用它作为

catch (Throwable t) { sneakyThrow(t); }
Run Code Online (Sandbox Code Playgroud)

正如Joachim Sauer评论的那样,在某些情况下,它有助于说服编译器线路调用sneakyThrow导致方法终止.我们只需更改声明的返回类型:

@SuppressWarnings("unchecked")
public static <T extends Throwable> T sneakyThrow(Throwable t) throws T {
    throw (T) t;
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

catch (Throwable t) { throw sneakyThrow(t); }
Run Code Online (Sandbox Code Playgroud)

出于教育目的,很高兴看到字节码级别发生了什么.以下相关摘录javap -verbose UncheckedThrower:

public static <T extends java.lang.Throwable> java.lang.RuntimeException sneakyThrow(java.lang.Throwable) throws T;
  descriptor: (Ljava/lang/Throwable;)Ljava/lang/RuntimeException;
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=1, locals=1, args_size=1
       0: aload_0
       1: athrow
  Exceptions:
    throws java.lang.Throwable
  Signature: #13                          // <T:Ljava/lang/Throwable;>(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;^TT;
Run Code Online (Sandbox Code Playgroud)

注意没有checkcast说明.该方法甚至合法地声明抛出任何T,这是擦除Throwable.

  • +1肯定是一个好主意,重命名`throwUnchecked(...)`?! (2认同)
  • @ billc.cn确切地说,这就是`@ SuppressWarnings`在那里做的事情:它警告你,你正在提交一个*未经检查的演员*,从这里开始,Java不保证输入安全性.我从Generics的一位作者那里读到了这一点:只要你得到**没有任何警告**来自编译器的是你的通用代码类型安全.在实践中,这种情况从未发生过,因为它甚至会剥夺我们对Generics提供的一点点帮助. (2认同)

Phi*_*ler 7

伟大的Guava库有一个方法Throwables.propagate(Throwable)可以完全执行您的代码:JavaDoc

来自doc:

如果它是RuntimeException或Error的实例,则按原样传播throwable,或者作为最后的手段,将它包装在RuntimeException中然后传播.