简单,一般兴趣,基于代码分析器的Java问题

时间:2009-10-17 15:55:42

标签: java findbugs pmd

好的,在使用 PMDFindBugs代码分析器查看了一些代码后,我能够对已审核的代码进行大量更改。但是,有些事情我不知道如何解决。我将在下面对它们进行迭代,并且(为了更好地参考)我会给每个问题一个数字。随意回答任何/所有人。谢谢你的耐心等待。

1。即使很难,我已经删除了一些规则,在重新评估代码之后,相关警告仍然存在。知道为什么吗?


2。请查看声明:

    private Combo comboAdress;

    private ProgressBar pBar;

以及getter和setter对对象的引用:

    private final Combo getComboAdress() {
  return this.comboAdress;
 }

 private final void setComboAdress(final Combo comboAdress) {
  this.comboAdress = comboAdress;
 }

 private final ProgressBar getpBar() {
  return this.pBar;
 }

 private final void setpBar(final ProgressBar pBar) {
   this.pBar = pBar;
 }

现在,我想知道为什么第一个声明没有给我任何关于PMD的警告,而第二个声明给了我以下警告:

Found non-transient, non-static member. Please mark as transient or provide accessors.

有关该警告的更多详情 here


3。这是PMD给出的另一个警告:

    A method should have only one exit point, and that should be the last statement in the method

有关该警告的更多详情 here

现在,我同意这一点,但如果我写这样的话会怎么样:

public void actionPerformedOnModifyComboLocations() {
    if (getMainTree().isFocusControl()) {
        return;
    }
    ....//do stuffs, based on the initial test
}

我倾向于同意该规则,但如果代码的性能提示多个退出点,我该怎么办?


4。 PMD给了我这个:

Found 'DD'-anomaly for variable 'start_page' (lines '319'-'322').

当我宣布类似的内容时:

String start_page = null;

我删除了这个信息(警告级别是信息),如果我将赋值删除为null,但是..我从IDE得到一个错误,说该变量可能是未初始化的,稍后在代码中。所以,我有点坚持。你可以做的最好的事情是禁止警告吗?


5。 PMD警告:

Assigning an Object to null is a code smell.  Consider refactoring.

这是单组态使用GUI组件的情况,或返回复杂对象的方法的情况。在catch()部分中将结果赋值为null,需要避免返回不完整/不一致的对象。是的,应该使用NullObject,但有些情况下我不想这样做。那我该不应该发出警告吗?


6。 FindBugs警告#1:

Write to static field MyClass.instance from instance method MyClass.handleEvent(Event)

方法

@Override
public void handleEvent(Event e) {
    switch (e.type) {
        case SWT.Dispose: {
            if (e.widget == getComposite()) {
                MyClass.instance = null;
            }
       break;
         }
    }
}

的静态变量

private static MyClass instance = null;

该变量允许我测试表单是否已经创建并且是否可见,并且在某些情况下我需要强制重新创建表单。我在这里看不到其他选择。任何见解? (MyClass实现了Listener,因此覆盖了handleEvent()方法)。


7。 FindBugs警告#2:

Class MyClass2 has a circular dependency with other classes

此警告基于其他类的简单导入显示。我是否需要重构这些导入才能使此警告消失?或者问题依赖于MyClass2?

好的,现在已经足够了。根据更多调查结果和/或您的答案,期待更新。感谢。

3 个答案:

答案 0 :(得分:2)

  1. 我不知道。似乎无论你做了什么,都不是你想做的事情!

  2. 也许声明出现在Serializable类中,但类型(例如ComboProgress本身不可序列化)。如果这是UI代码,那么这似乎很有可能。我只想评论该类,以表明它不应该被序列化。

  3. 这是一个有效的警告。因此,您可以重构代码:

    public void actionPerformedOnModifyComboLocations() {
        if (!getMainTree().isFocusControl()) {
            ....//do stuffs, based on the initial test
        }
    }
    
  4. 这就是我无法忍受静态分析工具的原因。 null任务显然会让您稍后开放NullPointerException。但是,有很多地方这是不可避免的(例如使用try catch finally使用Closeable进行资源清理)

  5. 这似乎也是一个有效的警告,大多数开发人员可能会将static访问权限视为代码嗅觉。考虑通过使用依赖注入进行重构,将资源跟踪器注入到当前使用静态的类中。

  6. 如果您的班级有未使用的导入,则应删除这些内容。此可能使警告消失。另一方面,如果需要导入,则可能具有真正的循环依赖关系,如下所示:

    class A {
        private B b;
    }
    class B {
        private A a;
    }
    
  7. 这通常是令人困惑的事务状态,让您对初始化问题持开放态度。例如,您可能会在A的初始化中意外添加一些代码,这些代码需要初始化B实例。如果您将相似的代码添加到B,那么循环依赖将意味着您的代码实际上已被破坏(即您无法构建AB

    再次举例说明为什么我真的不喜欢静态分析工具 - 它们通常只会为您提供一堆误报。循环相关的代码可以很好地工作,并且记录得非常好。

答案 1 :(得分:2)

以下是我对你的一些问题的回答:


问题编号 2

我认为你没有正确地利用这些房产。这些方法应该被称为getPBar和setPBar。

String pBar;

void setPBar(String str) {...}
String getPBar() { return pBar};

JavaBeans规范声明:

  

对于可读属性,将有一个getter方法来读取属性值。对于可写属性,将有一个setter方法来允许更新属性值。 [...]通过使用getFoo和setFoo访问器方法为遵循标准Java约定的属性构造PropertyDescriptor。因此,如果参数名称是“fred”,则它将假定reader方法是“getFred”并且writer方法是“setFred”。请注意,属性名称应以小写字符开头,该字符将在方法名称中大写。


问题编号 3

我同意您使用的软件的建议。为了便于阅读,只有一个出口点更好。为了提高效率,使用'return;'可能会更好。我的猜测是编译器足够聪明,总能选择有效的替代方案,我敢打赌,在这两种情况下,字节码都是相同的。

进一步的经验信息

我做了一些测试,发现我正在使用的java编译器(Mac OS X 10.4上的javac 1.5.0_19)没有应用我期望的优化。

我使用以下类来测试:

public abstract class Test{

  public int singleReturn(){   
     int ret = 0;
     if (cond1())
         ret = 1;
     else if (cond2())
         ret = 2;
     else if (cond3())
         ret = 3;

    return ret;
  }

  public int multReturn(){
    if (cond1()) return 1;
    else if (cond2()) return 2;
    else if (cond3()) return 3;
    else return 0;
  }

  protected abstract boolean cond1();
  protected abstract boolean cond2();
  protected abstract boolean cond3();
}

然后,我分析了字节码,发现对于multReturn(),有几个'ireturn'语句,而singleReturn()只有一个。此外,singleReturn()的字节码还包含几个返回语句的 goto

我用cond1,cond2和cond3的非常简单的实现测试了这两种方法。我确保这三个条件同样可以证明。我发现时间差异在3%到6%之间,支持multReturn()。在这种情况下,由于操作非常简单,多次返回的影响非常明显。

然后我使用cond1,cond2和cond3的更复杂的实现来测试这两种方法,以使不同回报的影响不那么明显。我对结果感到震惊!现在,multReturn()始终而不是singleReturn()(介于2%和3%之间)。我不知道是什么导致了这种差异,因为其余的代码应该是相同的。

我认为这些意外结果是由JVM的JIT编译器引起的。

无论如何,我坚持我最初的直觉:编译器(或JIT)可以优化这些事情,这使开发人员可以专注于编写易于阅读和维护的代码。


问题编号 6

您可以从实例方法中调用类方法,并将该静态方法改为类变量。

然后,您的代码类似于以下内容:

public static void clearInstance() {
    instance = null;
}

@Override
public void handleEvent(Event e) {
    switch (e.type) {
        case SWT.Dispose: {
            if (e.widget == getComposite()) {
                MyClass.clearInstance();
            }
       break;
         }
    }
}

这会引起您在5中描述的警告,但必须有一些妥协,在这种情况下,它只是一种气味,而不是错误。


问题编号 7

这只是一个可能问题的气味。它不一定是坏或坏,你不能确定只使用这个工具。

如果你有一个真正的问题,比如构造函数之间的依赖关系,测试应该显示它。

一个不同但相关的问题是jar之间的循环依赖关系:虽然可以编译具有循环依赖关系的类,但由于类加载器的工作方式,无法在JVM中处理jar之间的循环依赖关系。

答案 2 :(得分:1)

对于第3点,现在大多数开发人员可能会说单一返回规则是完全错误的,并且平均导致更糟糕的代码。其他人认为它是一个写下来的规则,具有历史凭据,一些破坏它的代码很难阅读,因此不遵循它是完全错误的。

您似乎同意第一个阵营,但没有信心告诉该工具关闭该规则。

要记住的是,在任何检查工具中编码是一个简单的规则,有些人确实需要它。所以它几乎总是由他们实现。

而很少(如果有的话)执行更主观的'后卫;身体;回报计算;'通常产生最容易阅读和最简单的代码的模式。

因此,如果您正在考虑生成良好代码,而不是简单地避免最差代码,那么您可能确实想要关闭一条规则。