一尘不染

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

java

我有这样的方法:

public void getSomething(){
...
}

我想抛出一个ExceptiongetSomething()。编译器不允许我这样做,因为不允许Exception将我的方法扔在那里。但是我需要抛出一个的子类来Exception进行测试
(我不能抛出UncheckedException。显然这是一个hack,但我需要进行测试。我尝试过EasyMock,但它也不允许我这样做。任何想法如何做到这一点?

谢谢,肖恩·阮


阅读 278

收藏
2020-12-03

共1个答案

一尘不染

方法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;
    }
}

诀窍依靠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);
    }
}

这是必需的,因为调用Unsafe.getUnsafe()通常会引发SecurityException。一旦有了实例,Unsafe就可以使用其强大的功能:

Unsafe unsafe = getUnsafe();
unsafe.throwException(new Exception());

值得信赖的是在帖子[http://codingdict.com/questions/4269)上的答案。我以为是出于完整性的考虑而提到了它,但是最好使用上面的技巧而不是允许您的代码进入。Unsafe


方法3:

在有关使用的链接答案的注释中Unsafe,@bestsss指出了不建议使用的方法简单得多的技巧Thread.stop(Throwable)

Thread.currentThread().stop(new Exception());

在这种情况下,您将@SuppressWarnings("deprecation")非常猛烈地使用并再次进行记录。同样,我比较喜欢它的(相对)清洁度。

2020-12-03