这些PMD规则的原因是什么?

36
DD和DU听起来很熟悉...我想说与最弱前置条件和后置条件相关的测试和分析之类的东西,但我不记得具体情况了。
NullAssignment: 给null赋值给对象是一种代码异味。请考虑重构。
如果对象是局部对象(在方法外部未使用),将对象设置为null是否有助于垃圾收集?还是那是一个谬论?
MethodArgumentCouldBeFinal: 参数'param'没有被分配,并且可以声明为final。 LocalVariableCouldBeFinal: 局部变量'variable'可以声明为final。
使用final参数和变量是否有任何优点?
LooseCoupling: 避免使用实现类型(例如'LinkedList');使用接口代替。
如果我知道我特别需要一个LinkedList,为什么我不使用它来明确向未来的开发人员表明我的意图?返回使最高类路径上最合理的类是一回事,但为什么我不声明我的变量为最严格的类型?
AvoidSynchronizedAtMethodLevel: 使用块级别而不是方法级别的同步。
块级别同步相比方法级别同步有什么优势?
AvoidUsingShortType: 不要使用short类型。
我的第一种语言是C和C++,但在Java世界中,为什么我不能使用最能描述我的数据类型?
6个回答

35
  • DD和DU异常(如果我没记错的话——我使用FindBugs,消息略有不同)指的是将一个值赋给一个从未被读取的本地变量,通常是因为在被读取之前就被重新赋值了。一个典型的情况是在声明变量时用null初始化一些变量。直到需要使用该变量时再声明它。

  • null分配给本地变量以“协助”垃圾收集器是错误的想法。PMD让您知道这只会产生无用的代码。

  • 在本地变量上指定final对于优化器应该非常有用,但我没有任何当前JIT利用此提示的具体示例。我发现它有助于推理自己代码的正确性。

  • 按照接口来指定接口是一个很好的设计实践。您可以轻松更改集合的实现而不会对调用方产生任何影响。这就是接口的全部意义。

  • 我想不出有多少情况下调用者会要求使用LinkedList,因为它没有暴露任何未在某些接口中声明的API。如果客户端依赖于该API,可以通过正确的接口获得。

  • 块级别的同步允许临界区更小,从而尽可能地并发执行尽可能多的工作。或许更重要的是,它允许使用由封闭对象私有控制的锁定对象。这样,您就可以保证不会发生死锁。如果将实例本身用作锁定,则任何人都可以错误地对其进行同步,从而导致死锁。

  • 任何操作中,类型为short的操作数都会被提升为int。这个规则是告诉你发生了这种提升,因此你可以使用int。不过,如果使用short类型可以节省内存,所以如果它是实例成员,我可能会忽略这个规则。


  • 任何操作中,类型为byte的操作数都会被提升为int类型。 - Ruslan López
    所以操作数的类型是char,但这与本问题无关。 - erickson

    3

    DataflowAnomalyAnalysis: 发现变量 'variable' 在行号 'n1'-'n2' 中存在 'DD'-异常。

    DataflowAnomalyAnalysis: 发现变量 'variable' 在行号 'n1'-'n2' 中存在 'DU'-异常。

    不知道。

    NullAssignment: 将对象赋值为 null 是一种代码异味。考虑重构。

    如果对象是局部对象(在方法外部未使用),将其设置为 null 是否有助于垃圾回收?或者这是一个谣言吗?

    在本地方法中的对象在方法返回后被标记为可进行垃圾回收。将它们设置为 null 不会有任何区别。

    由于它会让经验较少的开发人员感到困惑,因此可能被视为代码异味。

    MethodArgumentCouldBeFinal: 参数 'param' 未被分配,可以声明为 final

    LocalVariableCouldBeFinal: 本地变量 'variable' 可以声明为 final

    使用 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();
         }
      } 
    

    假设你被指派解决一些神秘的错误,有时会导致房屋着火。您知道使用了哪个参数,但不理解为什么(根据您的发现)如果条件不满足,则调用burnTheHouse方法的原因。某人在中途更改了引用,而您正在使用其他对象。使用final可以帮助防止这种情况发生。松耦合:避免使用实现类型(如'LinkedList'),而是使用接口。在这种情况下没有区别。我认为,由于您未使用LinkedList特定功能,因此该建议是合理的。今天,LinkedList可能是有意义的,但通过使用接口,您可以帮助自己(或他人)在不需要时轻松更改它。对于小型个人项目,这可能根本没有意义,但由于您已经在使用分析器,我想您已经关心代码质量了。此外,还可帮助不太有经验的开发人员养成良好习惯。避免在方法级别同步:使用块级别而不是方法级别同步。较小的同步部分越好。另外,如果您在方法级别同步,将阻止整个对象。当您在块级别同步时,只需同步该特定部分,在某些情况下,这正是您需要的。不要使用短类型。我从未听说过这个,我同意你的看法:)虽然我从未使用过short。我的猜测是,通过不使用它,您将帮助自己无缝升级到int。代码异味更注重代码质量而不是性能优化。因此,建议是为了避免陷阱和帮助不太有经验的程序员,而不是为了提高程序速度。这样,当尝试更改代码以适应更好的设计时,您可以节省大量时间和挫折。
    如果建议不合理,就忽略它们,记住,你是负责开发的人,而工具只是一个工具。如果出了问题,你不能责怪工具,对吧?

    3

    关于final问题的说明。

    将"final"放在变量上意味着它只能被赋值一次。这并不一定意味着更容易编写,但肯定意味着对于未来的维护者来说更容易阅读。

    请考虑以下几点:

    • 任何带有final的变量都可以立即归类为"在观察时不会改变值"。
    • 由此可以推断,如果所有不会改变的变量都标记为final,则未标记为final的变量实际上将会改变。

    这意味着在阅读定义部分时,您已经可以看出哪些变量可能在代码中改变值,因此维护者可以更好地花费精力,因为代码更易读。


    1

    如果对象是局部对象(不在方法之外使用),将对象设置为null是否有助于垃圾回收?或者这是一个谣言?

    它唯一的作用就是使得对象可以在方法结束之前被GC回收,这很少是必要的。

    使用final参数和变量有什么优点吗?

    它使代码更清晰,因为您不必担心分析代码时值是否会在某个地方更改。通常情况下,一旦设置了变量的值,您不需要或不想更改它的值。

    如果我知道我明确需要LinkedList,为什么我不使用它来明确向未来的开发人员表达我的意图?

    您能想到任何需要特定使用LinkedList的原因吗?

    返回最高级别的类路径的类是一回事,但为什么我不声明我的变量是最严格的呢?

    我不太在意局部变量或字段,但是如果您声明了一个LinkedList类型的方法参数,我会追踪并伤害您,因为这使得我无法使用像Arrays.asList()Collections.emptyList()之类的东西。

    块级同步与方法级同步相比有哪些优势?

    最大的优势在于它使您能够使用专用监视器对象,以便仅互斥那些需要互斥的关键部分,而不是所有使用相同监视器的内容。

    在Java世界中,为什么不应该使用最能描述我的数据类型?

    因为小于int的类型在所有计算中都会自动升级为int,您必须转换才能将任何内容分配给它们。这会导致混乱的代码和相当多的困惑(特别是涉及到自动装箱时)。


    0
    块级同步与方法级同步相比有哪些优势?同步一个方法就像执行一个synchronize(getClass())块,会阻塞整个类。也许你不想要这样。

    0

    AvoidUsingShortType: 不要使用short类型

    • 列表项

      在Java中,short是16位的2进制补码。

    • 任何与Integer家族中的另一个short以外的类型进行short数学运算都需要进行运行时符号扩展转换到更大的尺寸。对浮点数进行操作需要符号扩展和非平凡的IEEE-754转换。

    • 没有找到证据,但是使用32位或64位寄存器时,在字节码级别上不再节省“处理器指令”。就处理器寄存器而言,你正在将小型汽车停放在半挂车的停车位上。

    • 如果您正在字节码级别上优化项目,那太棒了。;P

    • 我同意在设计方面忽略这个pmd警告,只需权衡准确描述对象与所产生的性能转换。

    • 在我看来,大多数机器上的性能损失微不足道。忽略这个错误。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接