这些 PMD 规则的原因是啥?
Posted
技术标签:
【中文标题】这些 PMD 规则的原因是啥?【英文标题】:What is the reason for these PMD rules?这些 PMD 规则的原因是什么? 【发布时间】:2010-12-09 13:57:25 【问题描述】:DataflowAnomalyAnalysis:找到 'DD'-变量'variable'的异常 (行'n1'-'n2')。
DataflowAnomalyAnalysis:找到 'DU' - 变量'variable'的异常 (行'n1'-'n2')。
DD 和 DU 听起来很熟悉……我想说的是与最弱的前后条件相关的测试和分析,但我不记得具体内容了。
NullAssignment:将对象分配给 null 是一种代码味道。考虑 重构。
如果对象是本地对象(不在方法之外使用),是否将对象设置为null
有助于垃圾回收?还是那是一个神话?
MethodArgumentCouldBeFinal:参数 'param' 未分配,可能是 最终宣布
LocalVariableCouldBeFinal:本地 可以声明变量“变量” 最终
使用final
参数和变量有什么好处吗?
LooseCoupling:避免使用 实现类型如 '链表';使用界面 而是
如果我知道我特别需要LinkedList
,为什么我不使用它来向未来的开发人员明确表达我的意图?返回有意义的类路径中最高的类是一回事,但为什么我不将我的变量声明为最严格的?
AvoidSynchronizedAtMethodLevel:使用 块级而不是方法级 同步
块级同步相比方法级同步有什么优势?
AvoidUsingShortType:不要使用 短型
我的第一门语言是 C 和 C++,但在 Java 世界中,我为什么不使用最能描述我的数据的类型?
【问题讨论】:
【参考方案1】:DD 和 DU 异常(如果我没记错的话——我使用 FindBugs 并且消息有点不同)是指将一个值分配给一个从未读取过的局部变量,通常是因为它以前被重新分配了另一个值被阅读。一个典型的情况是在声明某个变量时使用null
对其进行初始化。 Don't declare the variable until it's needed.
将null
分配给局部变量以“帮助”垃圾收集器是一个神话。 PMD 让您知道这只会适得其反。
在局部变量上指定 final 应该对优化器非常有用,但我没有任何当前 JIT 利用此提示的具体示例。我发现它在推理我自己的代码的正确性时很有用。
根据...指定接口,接口 是一种很好的设计实践。您可以轻松更改集合的实现而不影响调用者。这就是接口的全部意义所在。
我想不出调用者会要求LinkedList
的许多情况,因为它不公开任何未由某个接口声明的 API。如果客户端依赖该 API,则可以通过正确的接口使用它。
块级同步允许关键部分更小,这允许尽可能多的工作同时完成。也许更重要的是,它允许使用由封闭对象私下控制的锁定对象。这样,您可以保证不会发生死锁。使用实例本身作为锁,任何人都可能在其上错误地同步,从而导致死锁。
short
类型的操作数在任何操作中都提升为 int
。此规则让您知道此促销正在发生,您不妨使用int
。但是,使用short
类型可以节省内存,所以如果它是实例成员,我可能会忽略该规则。
【讨论】:
字节类型的操作数在任何操作中也被提升为 int。char
类型的操作数也是如此,但这也与这个问题无关。【参考方案2】:
DataflowAnomalyAnalysis:找到 'DD'-变量'variable'的异常 (行'n1'-'n2')。
DataflowAnomalyAnalysis:找到 'DU' - 变量'variable'的异常 (行'n1'-'n2')。
不知道。
NullAssignment:将对象分配给 null 是一种代码味道。考虑 重构。
如果对象是本地对象(不在方法之外使用),是否将对象设置为
null
有助于垃圾回收?还是那是一个神话?
一旦方法返回,本地方法中的对象将被标记为垃圾回收。将它们设置为 null 不会有任何区别。
因为它会使开发人员缺乏经验,所以关于它的 null 赋值可能被认为是代码异味。
MethodArgumentCouldBeFinal:参数 'param' 未分配,可能是 最终宣布
LocalVariableCouldBeFinal:本地 可以声明变量“变量” 最终
使用
final
参数和变量有什么好处吗?
更清楚地表明,值在对象的生命周期内不会改变。
此外,如果有人尝试分配一个值,编译器将在编译类型时防止此编码错误。
考虑一下:
public void businessRule( SomeImportantArgument important )
if( important.xyz() )
doXyz();
// some fuzzy logic here
important = new NotSoImportant();
// add for/if's/while etc
if( important.abc() ) // <-- bug
burnTheHouse();
假设你被指派去解决一个不时烧毁房子的神秘虫子。
你知道什么浪费了参数,你不明白的是WHY如果条件不满足,就会调用burnTHeHouse
方法(根据你的发现)
您会花一些时间发现在中间的某个点,somone 更改了引用,并且您正在使用 other 对象。
使用final
有助于防止此类事情发生。
LooseCoupling:避免使用 实现类型如 '链表';使用界面 而是
如果我知道我特别需要
LinkedList
,为什么我不使用它来向未来的开发人员明确表达我的意图?返回有意义的类路径中最高的类是一回事,但为什么我不声明我的变量是最严格的?
在这种情况下没有区别。我认为由于您没有使用 LinkedList
特定功能,因此该建议是公平的。
今天,LinkedList 可能是有意义的,但是通过使用一个界面,您可以帮助您自己(或其他人)轻松地更改它。
对于小型的个人项目,这可能根本没有意义,但由于您已经在使用分析器,我猜您已经关心代码质量了。
此外,还可以帮助经验不足的开发人员养成良好的习惯。 [我不是说你是其中之一,但分析器不认识你;)]
AvoidSynchronizedAtMethodLevel:使用 块级而不是方法级 同步
块级同步相比方法级同步有什么优势?
同步部分越小越好。就是这样。
此外,如果您在方法级别进行同步,您将阻塞整个对象。当您在块级别同步时,您只需同步该特定部分,在某些情况下这就是您需要的。
AvoidUsingShortType:不要使用 短型
我的第一门语言是 C 和 C++,但在 Java 世界中,我为什么不使用最能描述我的数据的类型?
我从来没有听说过这个,我同意你的看法:) 不过我从来没有使用过short。
我的猜测是,如果不使用它,您将帮助自己无缝升级到int
。
代码异味更注重代码质量而不是性能优化。因此,建议是针对经验不足的程序员并避免陷阱,而不是提高程序速度。
这样,您可以在尝试更改代码以适应更好的设计时节省大量时间和麻烦。
如果建议没有意义,请忽略它们,记住,您是负责的开发人员,而工具只是一个工具。如果出现问题,你不能责怪工具,对吧?
【讨论】:
【参考方案3】:只是关于final
问题的注释。
将“final”放在变量上会导致它只能赋值一次。这并不一定意味着它更容易编写,但肯定意味着它更容易阅读未来的维护者。
请考虑以下几点:
任何带有final
的变量都可以立即归类为“观看时不会改变值”。
隐含的意思是,如果所有不会改变的变量都用final标记,那么没有用final标记的变量实际上会改变。
这意味着您在阅读定义部分时已经可以看到要注意哪些变量,因为它们可能会在代码期间改变值,并且维护者可以更好地花费他/她的努力,因为代码更具可读性。
【讨论】:
【参考方案4】:不会将对象设置为 null 协助垃圾收集,如果 object 是本地对象(未使用 方法之外)?或者那是一个 神话?
它所做的唯一一件事就是让对象在方法结束之前被 GCd 成为可能,这很少需要。
使用最终参数和变量有什么好处吗?
它使代码更加清晰,因为您不必担心在分析代码时某个地方的值会发生变化。更常见的是,一旦设置了变量,您就不需要或不想更改它的值。
如果我知道我特别需要 LinkedList,我为什么不用一个来 明确表达我的意图 未来的开发商?
你能想出什么理由让你特别需要一个 链表?
这是一回事 返回最高的班级 有意义的类路径,但为什么 我不会将我的变量声明为 最严格意义上的?
我不太关心局部变量或字段,但是如果你声明一个LinkedList
类型的方法参数,我会追捕你并伤害你,因为它使我无法使用@987654322之类的东西@ 和Collections.emptyList()
。
块级同步相比方法级同步有什么优势?
最大的一个是它使您能够使用专用的监视器对象,以便只有那些需要互斥的关键部分,而不是使用同一个监视器。
在 Java 世界里,我为什么不应该 使用最能描述我的类型 数据?
因为对于所有计算,小于 int 的类型都会自动提升为 int,并且您必须向下转换才能为它们分配任何东西。这会导致代码混乱和混乱(尤其是在涉及自动装箱时)。
【讨论】:
【参考方案5】:AvoidUsingShortType:不要使用短类型
列表项
short 是 16 位,java 中 2 的补码
对于 Integer 系列中的任何东西在另一个短之外的短数学运算将需要运行时符号扩展转换为更大的大小。对浮点进行操作需要符号扩展和到 IEEE-754 的重要转换。
找不到证据,但是使用 32 位或 64 位寄存器,您不再需要在字节码级别节省“处理器指令”。就处理器寄存器而言,您将一辆紧凑型汽车停在半挂车的停车位。
如果您正在字节码级别优化您的项目,哇。哇。 ;P
我同意忽略此 pmd 警告的设计方面,只需权衡准确地用“短”描述您的对象与产生的性能转换。
在我看来,在大多数机器上产生的性能损失是微不足道的。忽略错误。
【讨论】:
【参考方案6】:块级有什么优势 同步有超过方法级别 同步? 同步一个方法就像做一个
synchronize(getClass())
块,并且阻塞所有的类。
也许你不想这样
【讨论】:
以上是关于这些 PMD 规则的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章