当您的方法签名不允许抛出异常时,如何抛出异常?
我有一个这样的方法:
public void getSomething(){
...
}
我想扔一个里面.编译器不允许我这样做,因为我的方法不允许在那里抛出。但是我需要为我的测试抛出一个子类(我不能抛出未检查的异常
)。这显然是一个黑客,但我需要它进行测试。我尝试过EasyMock,但它也不允许我这样做。任何想法如何做到这一点?Exception
getSomething()
Exception
Exception
谢谢,肖恩·阮
我有一个这样的方法:
public void getSomething(){
...
}
我想扔一个里面.编译器不允许我这样做,因为我的方法不允许在那里抛出。但是我需要为我的测试抛出一个子类(我不能抛出未检查的异常
)。这显然是一个黑客,但我需要它进行测试。我尝试过EasyMock,但它也不允许我这样做。任何想法如何做到这一点?Exception
getSomething()
Exception
Exception
谢谢,肖恩·阮
方法 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
E
RuntimeException
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());
功劳归于帖子 https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe 上的这个答案。我想我会提到这一点以保持完整性,但最好只是使用上面的技巧,而不是允许进入你的代码。Unsafe
方法 3:
在关于使用 的链接答案的评论中,@bestsss指出了使用已弃用的方法 Thread.stop(Throwable)
的一个更简单的技巧:Unsafe
Thread.currentThread().stop(new Exception());
在这种情况下,您将非常激烈地使用并再次记录。同样,我更喜欢第一个技巧,因为它的(相对)清洁度。@SuppressWarnings("deprecation")
Java 有两种异常:选中和未选中。必须声明已选中的异常,但不必声明未选中的异常。
RuntimeException
是基本的未选中异常,因此您可以在不声明它的情况下引发它。
public void getSomething(){
throw new RuntimeException("I don't have to be declared in the method header!");
}
作为旁注,您可能不想抛出原始的 RuntimeException,而是将其子类化为更特定于您的需求的内容。RuntimeException 的任何子类也将被取消选中。