来自PMD的数据流异常分析警告

23

我正在使用带有 PMD Plug-in (4.0.0.v20130510-1000) 的 Eclipse,并且遇到了很多这些违规情况:

发现变量 'freq' 的 'DD' 异常(行 '187'-'189')。
发现变量 'freq' 的 'DU' 异常(行 '189'-'333')。

这个 SO 答案中,它说这些异常与分配从未被读取的值有关。但是我在这种情况下也会出现违规情况:

// here I get a DD anomaly
double freq = 0;
try {
  // here I get a DU anomaly
  freq = Double.parseDouble(getFrequencyTextField().getText());
} catch (final NumberFormatException e) {
  Log.e(e.getMessage());
}
if (freq < 10E6) doSomething();

如果我删除初始化并在catch块中添加freq = 0;一行,则DD异常消失,但两个赋值语句都会出现DU异常。

现在我的问题是:我应该如何处理?PMD的首选解决方案是什么?这条规则到底试图防止什么(即为什么它是不好的做法)?

2个回答

24
double freq; // (1)
try {
  // here I get a DU anomaly
  freq = Double.parseDouble(getFrequencyTextField().getText());
} catch (final NumberFormatException e) {
  Log.e(e.getMessage());
  freq = 0; // (2)
}
if (freq < 10E6) doSomething();

第一个问题在于,在catch语句中,parseDouble赋值没有被执行到freq上。 如果出现异常,freq仍然为0。可能需要标记。 因此,在catch中对freq进行赋值后,问题就解决了。

当在catch中对freq进行赋值时,(2)中的初始赋值(1)将不会被读取,因此只需声明即可。

关于更好的代码风格:

try {
  // here I get a DU anomaly
  double freq = Double.parseDouble(getFrequencyTextField().getText());

  if (freq < 10E6) doSomething();
  ...

} catch (final NumberFormatException e) {
  Log.e(e.getMessage());
}

或者按照 @JoachimSauer 的答案,使用不会抛出异常的双重转换。日志记录将指示优先采用上述样式的严重程度。在错误的简单转换函数内部记录日志可能并不是好的风格:太多日志、被忽略的日志(?)、难以修复。


谢谢你的解释,这让我明白了很多。还要感谢你的建议。我一直很欣赏代码风格的纠正。(这也是我开始使用PMD的原因。) - brimborium

4
你可以通过将解析操作提取到一个单独的方法中来解决这个问题(并更清晰地分离关注点):
double freq = parseDouble(getFrequencyTextField().getText());

// later in the class (or in a utility class):

public static double parseDouble(final String input) {
  try {
    return Double.parseDouble(input);
  } catch (final NumberFormatException e) {
    Log.e(e.getMessage());
    return 0;
  }
}

如果你有不同的默认值,你也可以添加一个带有两个参数的版本:public static double parseDouble(final String input, final double defaultValue)


我喜欢默认值的想法。我想我会这样做。尽管在那个例子中,我只得到了下一个PMD违规:方法应该只有一个出口点,并且应该是方法中的最后一个语句. - brimborium
@brimborium:那个警告创建了一个丑陋的语义循环:我看不到避免同时出现两种警告的(简单)解决方案。 - Joachim Sauer
是的,我倾向于将规则集中的第二条规则删除。虽然我理解它的意义。如果只有一个退出点,那么更容易理解复杂方法的完整含义... - brimborium
1
个人而言,我完全不赞同“单一出口点”规则。它经常使代码变得毫无必要的复杂。我会用“不要在意料之外的地方使用退出点”规则来代替它,但这可能稍微难以由静态分析器检测。;-) - Joachim Sauer
1
在 catch 块中使用 return 总是不好的。如果添加了 finally 块,代码会变得混乱。 - BevynQ
@BevynQ:我不同意。有时在catch中返回值正是你想要做的(比如这种情况)。然而,在final中返回值则是纯粹的邪恶行为。 - Joachim Sauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接