当方法签名不允许抛出exception时,如何抛出exception?
我有这样的方法:
public void getSomething(){ ... }
我想在getSomething()
抛出一个Exception
。 编译器不允许我这样做,因为我的方法不允许在那里抛出exception。 但我需要为我的测试抛出一个Exception
的子类(我不能抛出Unchecked Exception
) 。 这显然是一个黑客,但我需要它进行测试。 我试过EasyMock,但它也不允许我这样做。 任何想法如何做到这一点?
谢谢,Sean Nguyen
方法1:
Alexey Ragozin的这篇文章描述了如何使用generics技巧来抛出未声明的已检查exception。 从那篇文章:
public class AnyThrow { public static void throwUnchecked(Throwable e) { AnyThrow.throwAny(e); } @SuppressWarnings("unchecked") private static void throwAny(Throwable e) throws E { throw (E)e; } }
该技巧依赖于throwUnchecked
“撒谎”给编译器,类型E
是RuntimeException
,调用throwAny
。 由于throwAny
被声明为throws E
,编译器认为特定的调用只能抛出RuntimeException
。 当然,通过throwAny
随意声明E
并盲目地向其投射,允许调用者决定其参数被强制转换为什么 – 诡异编码时可怕的设计。 在运行时, E
被删除 ,没有任何意义。
正如你所指出的,做这样的事情是一个巨大的黑客攻击,你应该很好地记录它的使用。
方法2:
你也可以使用sun.misc.Unsafe
来实现这一目的。 首先,您必须实现一个使用reflection来返回该类实例的方法:
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
实例后,您可以使用其可怕的function:
Unsafe unsafe = getUnsafe(); unsafe.throwException(new Exception());
在https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe上发布了这个答案 。 我想我会提到这个是为了完整性,但是最好只使用上面的技巧而不是让Unsafe
进入你的代码。
方法3:
在关于使用Unsafe
的链接答案的评论中, @ bestsss使用弃用的方法Thread.stop(Throwable)
指出了一个更简单的技巧:
Thread.currentThread().stop(new Exception());
在这种情况下,您将使用@SuppressWarnings("deprecation")
并再次以非常激烈的方式记录。 同样,我更喜欢它(相对)清洁度的第一招。
Java有两种例外,检查和未检查。 您必须声明已检查的exception,但不必声明未经检查的exception。
RuntimeException
是基本的未经检查的exception,因此您可以抛出它而不声明它。
public void getSomething(){ throw new RuntimeException("I don't have to be declared in the method header!"); }
作为旁注,您可能不希望抛出原始的RuntimeException,而是将其子类化为更符合您需求的内容。 RuntimeException的任何子类也将被取消选中。
我不知道你想做什么。 您可以在方法中抛出未经检查的exception,然后使用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()); } }