在总是抛出方法之后如何检测死代码?

How can I detect dead code after always-throwing methods?

考虑以下代码:

@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() 的调用将总是 抛出异常。

所以我是

a) 很惊讶编译器不能告诉我 "this is dead code"

b) 想知道是否有一些编译器标志(或 eclipse 设置)会导致告诉我:你那里有死代码。

旨在进行全面的单元测试并衡量测试的测试覆盖率。死代码会很明显,因为 none 的测试导致它被执行。

死代码编译时错误由编译器定义,而不是 IDE。虽然代码确实永远不会执行,但它并不违反 Oracle 文档中关于无法访问语句的任何规则。

来自Unreachable Statements

This section is devoted to a precise explanation of the word "reachable." The idea is that there must be some possible execution path from the beginning of the constructor, method, instance initializer, or static initializer that contains the statement to the statement itself. The analysis takes into account the structure of statements. Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.

本案例的具体规则与您创建的块是否可达有关。 (iff = 当且仅当)

An empty block that is not a switch block can complete normally iff it is reachable.

A non-empty block that is not a switch block can complete normally iff the last statement in it can complete normally.

The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable.

Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.

letsThrow 方法符合工作代码块的标准,技术上 正常完成 。它抛出一个异常,但它完成了。在确定该代码块是否在其实际使用中时,不考虑它是否抛出有保证的异常,只是是否可以到达。在大多数情况下,死代码只有在涉及 try/catch/returns 时才会被发现,这是大部分规则。

考虑以下更简洁的版本:

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

除了勤奋地使用覆盖工具之外,没有真正的应对方法,但在您的示例中,好的一面是您每次 运行 代码时都会看到有保证的异常。

将您的方法声明为return可抛出类型:

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

那你调用的时候就可以抛:

throw letsThrow();

现在,调用 letsThrow() 之后的任何代码都将被检测为无效。

您可以通过使用静态分析工具检查未使用 letsThrow() 的 return 值的情况来强制执行此操作。例如,Google's errorprone has a checker for the @CheckReturnValue annotation 确保您使用结果。

(对于穷人的版本,搜索正则表达式 ^\s*letsThrow();)。