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

时间:2012-08-13 21:58:57

标签: java exception checked-exceptions

我有这样的方法:

public void getSomething(){
...
}

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

谢谢, Sean Nguyen

3 个答案:

答案 0 :(得分:22)

方法1:

This post by 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“骗”编译器,E类型为RuntimeException并调用throwAny。由于throwAny被声明为throws E,编译器认为特定调用只能抛出RuntimeException。当然,通过throwAny任意声明E并盲目地向它投射,允许调用者决定它的参数是什么 - 在编码时的可怕设计 - 使得诀窍成为可能。在运行时,Eerased,没有任何意义。

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


方法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());

信用转到帖子this answer上的https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe。我认为我会提到这一点是为了完整性,但最好只使用上面的技巧而不是允许Unsafe进入你的代码。


方法3:

在关于使用Unsafe的关联答案的评论中,@bestsss points out使用弃用的方法Thread.stop(Throwable)更简单的技巧:

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

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

答案 1 :(得分:2)

Java有两种例外,检查和取消选中。您必须声明已检查的异常,但不必声明未经检查的异常。

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

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

作为旁注,您可能不希望抛出原始的RuntimeException,而是将其子类化为更符合您需求的内容。 RuntimeException的任何子类也将被取消选中。

答案 2 :(得分:0)

我不知道你要做什么。您可以在方法中抛出未经检查的异常,然后使用JUnit进行测试,如下例所示。

public void getSomething() {
    throw new RuntimeException();
}

JUnit 4测试示例:

@Test
public void testGetSomething() {
    try {
        getSomething();
        fail("Expecting RuntimeException!");
    } catch (Exception e) {
        Logger.getLogger("test").info("Exception was caught: " + e.getClass());
    }
}