2012-08-13 24 views
17

我有这样的方法:如何在您的方法签名不允许抛出异常时抛出异常?

public void getSomething(){ 
... 
} 

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

感谢, 肖恩阮

+0

您正在测试的东西,是不可能发生的。为什么? – rodrigoap 2012-08-13 22:13:46

+0

我试图用LogicalHandler 来模拟soap响应。 handleMessage(LogicalMessageContext上下文)不会声明抛出异常。但是,所有由soap结束点引发的异常都是Exceptions的子类。我需要抛出这些异常来模拟我的服务响应。 – 2012-08-13 22:16:46

+0

如果您有兴趣,请查看我的编辑。 – 2012-09-06 00:31:55

回答

19

方法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“说谎”到编译器的类型ERuntimeException其调用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:

在链接答案的评论有关使用过时的方法Thread.stop(Throwable)使用Unsafe@bestsss points out一个更简单的把戏:

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

在这种情况下,你会使用@SuppressWarnings("deprecation")并再次证明文件非常激烈。再次,我更喜欢它的(相对)清洁度的第一招。

+0

非常感谢。有用! – 2012-08-14 16:10:03

+0

@PaulBellora你总是可以使用'Class :: newInstance()'方法来玩游戏,它会抛出任何东西 – emesx 2013-06-16 08:15:10

+0

@PaulBellora为什么第一个例子在运行时不会导致'ClassCastException'? – Demi 2014-04-26 15:50:37

1

Java有两种异常,检查并选中。您必须声明已检查的异常,但您不必声明未检查的异常。

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

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

作为一个侧面说明,你可能不想抛出RuntimeException的原料,但它继承更具体的您的需要的东西。 RuntimeException的任何子类也将被取消选中。

+0

我很抱歉不清楚。我需要抛出java.lang.Exception的一个子类(checked异常)。 – 2012-08-13 22:11:20

+3

@SeanNguyen RuntimeException是Exception的子类。这只是Java中的一个特例,你不需要声明它会被抛出。 – Oleksi 2012-08-13 22:12:18

+0

对不起,再次不太清楚。我需要抛出异常的子类的检查异常。我不能抛出RuntimeException。 – 2012-08-13 22:22:17

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()); 
    } 
}