2016-06-08 36 views
7

考慮下面的代碼:如何在始終拋出方法後檢測死代碼?

@Test 
public void testDeadCode() { 
    letsThrow(); 
    System.out.println("will never be reached"); 
} 

private final void letsThrow() { 
    throw new RuntimeException("guess you didnt see this one coming"); 
} 

在我看來絕對不可能的println()一樣都不會被執行 - 因爲調用letsThrow()將總是拋出異常。

因此我

一)意外的是,編譯器不能告訴我,「這是死代碼」

B)如果有一些編譯器標誌(或者Eclipse設置),這將導致疑惑告訴我:你在那裏得到了死碼。

+1

想象一下在'letsThrow()'方法中有很多內部方法調用的情況,但代碼要複雜得多。你是否要求編譯器檢查這種情況下的死代碼?編譯器不是全能的。 – SimY4

+0

最好的方法是徹底的單元測試和三葉草代碼覆蓋率檢查,它會告訴你哪些代碼永遠不會執行 – Kode

+0

@Vwin不是真的。使我問的代碼看起來像是catch(無論w){tuneAndRethrow(w);拋出Bla(w); }'所以只有一行死代碼。這意味着我需要接近100%的覆蓋率才能找到這些地方。聽起來不像是對我的真正計劃。 – GhostCat

回答

4

死代碼編譯時錯誤由編譯器而不是IDE定義。雖然這是真的,但代碼永遠不會被執行,它不會違反任何Oracle Docs中不可達語句的規則。

Unreachable Statements

這部分是專門用於單詞的精確的解釋「可達」。這個想法是,從構造函數,方法,實例初始化程序或包含聲明本身的語句的靜態初始化程序開始,必須存在一些可能的執行路徑。分析考慮到了陳述的結構。除了對while,do和do的特殊處理外,對於條件表達式具有常數值true的語句,流式分析中不考慮表達式的值。

專門針對這種情況的規則與您創建的塊是否可達有關。 (iff =當且僅當)

如果它是可到達的,則不是開關塊的空塊可以正常完成。

如果其中的最後一條語句可以正常完成,那麼非正常的非空塊​​可以正常完成。

如果塊可到達,非空塊中的第一條語句可以訪問,而非非空塊。

如果前面的語句S可以正常完成,那麼非空塊中的每個其他語句S都不可以被訪問。

letsThrow方法滿足的標準的碼工作塊上和技術上通常完成。它拋出一個異常,但它完成。在確定它在實際使用中是否代碼塊僅僅是否可以達到時,是否考慮它是否引發保證的異常。在大多數情況下,死代碼僅在涉及try/catch/returns(大部分規則)時才能找到。

考慮以下,更加簡潔的版本:

@Test 
public void testDeadCode() { 
    System.exit(0); 
    System.out.println("will never be reached"); 
} 

有這個沒有真正的櫃檯除了勤奮使用覆蓋工具,但光明的一面在你的例子是,每次你會看到保證例外你運行代碼。

0

旨在進行全面的單元測試並測試測試的測試覆蓋率。死代碼會很明顯,因爲沒有你的測試導致它被執行。

+0

請參閱我對上述Vwins評論的評論。 – GhostCat

0

聲明你的方法返回一個拋出類型:

private final RuntimeException letsThrow() { 
    throw new RuntimeException("guess you didnt see this one coming"); 
} 

然後當你調用它,你可以拋出:

throw letsThrow(); 

現在,它遵循調用letsThrow()將可檢測的任何代碼死。

您可以通過檢查使用靜態分析工具未使用返回值letsThrow()的情況來強制執行此操作。例如,Google's errorprone has a checker for the @CheckReturnValue annotation可確保您使用結果。

(對於窮人的版本,搜索正則表達式^\s*letsThrow();)。

+0

有趣的想法。但我想我會更喜歡'letsThrow()'不要拋棄 - 其他任何東西似乎要求一個「跆拳道代碼質量指標」數字... – GhostCat

+0

我不明白 - 如果你不想'letsThrow ()'不要扔,爲什麼呢? –

+1

我的意思是:只有「內擲」纔會發生。但是你需要深入瞭解這一點。如果你已經知道someCall()本身會拋出,似乎誤導讀者編寫'throw someCall()'。我明白這個構造解決了我的問題;但如果我爲此付出努力,我寧願重寫'letsThrow()'以僅返回,而不是拋出! – GhostCat

相關問題