好的,在使用 PMD和FindBugs代码分析器查看了一些代码后,我能够对已审核的代码进行大量更改。但是,有些事情我不知道如何解决。我将在下面对它们进行迭代,并且(为了更好地参考)我会给每个问题一个数字。随意回答任何/所有人。谢谢你的耐心等待。
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?
好的,现在已经足够了。根据更多调查结果和/或您的答案,期待更新。感谢。
答案 0 :(得分:2)
我不知道。似乎无论你做了什么,都不是你想做的事情!
也许声明出现在Serializable
类中,但类型(例如ComboProgress
本身不可序列化)。如果这是UI代码,那么这似乎很有可能。我只想评论该类,以表明它不应该被序列化。
这是一个有效的警告。因此,您可以重构代码:
public void actionPerformedOnModifyComboLocations() {
if (!getMainTree().isFocusControl()) {
....//do stuffs, based on the initial test
}
}
这就是我无法忍受静态分析工具的原因。 null
任务显然会让您稍后开放NullPointerException
。但是,有很多地方这是不可避免的(例如使用try catch finally
使用Closeable
进行资源清理)
这似乎也是一个有效的警告,大多数开发人员可能会将static
访问权限视为代码嗅觉。考虑通过使用依赖注入进行重构,将资源跟踪器注入到当前使用静态的类中。
如果您的班级有未使用的导入,则应删除这些内容。此可能使警告消失。另一方面,如果需要导入,则可能具有真正的循环依赖关系,如下所示:
class A {
private B b;
}
class B {
private A a;
}
这通常是令人困惑的事务状态,让您对初始化问题持开放态度。例如,您可能会在A
的初始化中意外添加一些代码,这些代码需要初始化B
实例。如果您将相似的代码添加到B
,那么循环依赖将意味着您的代码实际上已被破坏(即您无法构建A
或B
。
再次举例说明为什么我真的不喜欢静态分析工具 - 它们通常只会为您提供一堆误报。循环相关的代码可以很好地工作,并且记录得非常好。
答案 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点,现在大多数开发人员可能会说单一返回规则是完全错误的,并且平均导致更糟糕的代码。其他人认为它是一个写下来的规则,具有历史凭据,一些破坏它的代码很难阅读,因此不遵循它是完全错误的。
您似乎同意第一个阵营,但没有信心告诉该工具关闭该规则。
要记住的是,在任何检查工具中编码是一个简单的规则,有些人确实需要它。所以它几乎总是由他们实现。
而很少(如果有的话)执行更主观的'后卫;身体;回报计算;'通常产生最容易阅读和最简单的代码的模式。
因此,如果您正在考虑生成良好代码,而不是简单地避免最差代码,那么您可能确实想要关闭一条规则。