2012-08-13 48 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()); 
    } 
}