当方法签名不允许抛出异常时,如何抛出异常?

Sea*_*yen 20 java exception checked-exceptions

我有这样的方法:

public void getSomething(){
...
}
Run Code Online (Sandbox Code Playgroud)

我想扔一个Exception内心getSomething().编译器不允许我这样做,因为我的方法不允许Exception在那里抛出.但我需要Exception为我的测试抛出一个子类(我不能抛出Unchecked Exception).这显然是一个黑客,但我需要它进行测试.我试过EasyMock,但它也不允许我这样做.任何想法如何做到这一点?

谢谢Sean Nguyen

Pau*_*ora 25

方法1:

Alexey Ragozin的这篇文章描述了如何使用泛型技巧来抛出未声明的已检查异常.从那篇文章:

public class AnyThrow {

    public static void throwUnchecked(Throwable e) {
        AnyThrow.<RuntimeException>throwAny(e);
    }

    @SuppressWarnings("unchecked")
    private static <E extends Throwable> void throwAny(Throwable e) throws E {
        throw (E)e;
    }
}
Run Code Online (Sandbox Code Playgroud)

诀窍依靠throwUnchecked"说谎"到编译器的类型ERuntimeException与它的调用throwAny.由于throwAny声明为throws E,编译器认为特定的调用可以抛出RuntimeException.当然,通过throwAny任意声明E并盲目地向它投射,允许调用者决定它的参数是什么来实现这个技巧- 在编码时做出可怕的设计.在运行时,E删除,没有任何意义.

正如你所指出的,做这样的事情是一个巨大的黑客,你应该很好地记录它的使用.


方法2:

你也可以用它sun.misc.Unsafe来做到这一点.首先,您必须实现一个使用反射来返回该类实例的方法:

private static Unsafe getUnsafe() {
    try {
        Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeField.setAccessible(true);
        return (Unsafe)theUnsafeField.get(null);
    }
    catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    }
    catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是必要的,因为调用Unsafe.getUnsafe()通常会抛出一个SecurityException.一旦有了实例,Unsafe就可以使用它的可怕功能:

Unsafe unsafe = getUnsafe();
unsafe.throwException(new Exception());
Run Code Online (Sandbox Code Playgroud)

/sf/ask/390196901/的帖子中获得了这个答案.我想我会提到这个是为了完整性,但是最好只使用上面的技巧而不是允许你的代码.Unsafe


方法3:

在关于使用的链接答案的评论中Unsafe,@ bestsss使用弃用的方法指出了一个更简单的技巧Thread.stop(Throwable):

Thread.currentThread().stop(new Exception());
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将使用@SuppressWarnings("deprecation")并再次非常激烈地记录.同样,我更喜欢它的(相对)清洁度的第一招.


Ole*_*ksi 5

Java 有两种异常,受控异常和非受控异常。您必须声明已检查异常,但不必声明未检查异常。

RuntimeException是基本的未经检查的异常,因此您可以在不声明的情况下抛出它。

public void getSomething(){
   throw new RuntimeException("I don't have to be declared in the method header!");
}
Run Code Online (Sandbox Code Playgroud)

附带说明一下,您可能不想抛出原始 RuntimeException,而是将其子类化为更适合您的需求的东西。RuntimeException 的任何子类也将被取消检查。

  • @SeanNguyen RuntimeException 是 Exception 的子类。这只是 Java 中的一种特殊情况,您不需要声明它将被抛出。 (3认同)