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

问题描述 投票:2回答:3

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

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


请看一下声明:

    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的更多细节。


这是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
}

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


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?

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

java findbugs pmd
3个回答
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. 我不知道。似乎无论你做了什么,都不是你想要做的!
  2. 也许声明出现在Serializable类中,但类型(例如ComboProgress本身不可序列化)。如果这是UI代码,那么这似乎很有可能。我只想评论该类,以表明它不应该被序列化。
  3. 这是一个有效的警告。您可以重构代码: public void actionPerformedOnModifyComboLocations() { if (!getMainTree().isFocusControl()) { ....//do stuffs, based on the initial test } }
  4. 这就是我无法忍受静态分析工具的原因。 null任务显然让你稍后对NullPointerExceptions开放。但是,有很多地方这是不可避免的(例如使用try catch finally使用Closeable进行资源清理)
  5. 这似乎也是一个有效的警告,你使用static访问可能被大多数开发人员认为是代码味道。考虑通过使用依赖注入进行重构,以将资源跟踪器注入到此时使用静态的类中。
  6. 如果您的类具有未使用的导入,则应删除这些导入。这可能会使警告消失。另一方面,如果需要导入,则可能具有真正的循环依赖关系,如下所示: class A { private B b; } class B { private A a; }

这通常是令人困惑的事态,让您对初始化问题持开放态度。例如,您可能会在A的初始化中意外添加一些代码,这些代码需要初始化B实例。如果你在B中添加类似的代码,那么循环依赖将意味着你的代码实际上被破坏了(即你无法构造AB

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


1
投票

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

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

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

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

因此,如果您正在考虑生成优秀的代码,而不是简单地避免使用最差的代码,那么您可能希望关闭这一规则。

© www.soinside.com 2019 - 2024. All rights reserved.