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



考虑以下代码:

@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) 很惊讶编译器不能告诉我"这是死代码">

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

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

来自无法访问的语句

本节专门对单词";可达"其思想是,从包含语句的构造函数、方法、实例初始化器或静态初始化器的开头到语句本身,必须有一些可能的执行路径。分析考虑了报表的结构。除了while、do和条件表达式具有常数值true的语句的特殊处理外,在流分析中不考虑表达式的值。

专门针对这种情况的规则与您创建的块是否可访问有关。(iff=当且仅当)

非开关块的空块可以正常完成,前提是它是可访问的。

非开关块的非空块可以正常完成,如果其中的最后一条语句可以正常完成。

非空块中的第一个语句不是交换机块,当该块是可访问的时,该语句是可访问。

在不是切换块的非空块中的每一个其他语句S都是可到达的,前提是S之前的语句可以正常完成。

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

考虑以下更简洁的版本:

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

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

旨在进行全面的单元测试,并测量测试的测试覆盖率。死代码将是显而易见的,因为您的任何测试都不会导致它被执行。

将方法声明为返回可丢弃类型:

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

然后你可以在你叫它的时候扔:

throw letsThrow();

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

您可以通过使用静态分析工具检查未使用letsThrow()返回值的情况来强制执行此操作。例如,Google的易出错程序有一个@CheckReturnValue注释的检查器,可以确保您使用结果。

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

相关内容

  • 没有找到相关文章

最新更新