【问题标题】:Dataflow anomaly analysis warnings from PMD来自 PMD 的数据流异常分析警告
【发布时间】:2013-05-19 02:00:29
【问题描述】:

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

Found 'DD'-anomaly for variable 'freq' (lines '187'-'189').
Found 'DU'-anomaly for variable 'freq' (lines '189'-'333').

this 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 的首选解决方案是什么?这条规则到底是为了防止什么(即为什么这是不好的做法)?

【问题讨论】:

    标签: java pmd dataflow anomaly-detection


    【解决方案1】:
    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 进行赋值。 在异常情况下,频率仍然为 0。可能是可标记的。 所以在catch内分配给freq时它就消失了。

    当在 catch (2) 中赋值给 freq 时,初始赋值 (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 的原因。)
    【解决方案2】:

    您可以通过将解析提取到单独的方法中来解决这个问题(并更清楚地分离关注点):

    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 违规:A method should have only one exit point, and that should be the last statement in the method
    • @brimborium:该警告创建了一个丑陋的语义循环:我认为没有(简单的)解决方案可以同时避免 both 警告。
    • 是的,我倾向于将第二条规则踢出规则集。虽然我明白这是重点。如果只有一个出口点,则更容易理解复杂方法的全部含义...
    • 我个人完全不同意单出口规则。它经常使代码变得不必要的复杂。我会将其替换为“在意外的地方没有出口点”规则,但是 可能 稍微难以检查静态分析器 ;-)跨度>
    • catch 块中的返回总是不好的。添加一个 finally 块,您的代码会令人困惑。
    猜你喜欢
    • 2020-10-08
    • 2013-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多