当方法签名不允许抛出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 “撒谎”给编译器,类型ERuntimeException ,调用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()); } }