简体   繁体   English

findbugs反对匿名内部类

[英]findbugs is objecting to anonymous inner class

This code: 这段代码:

Set<Map.Entry<String, SSGSession>> theSet =  new TreeSet<Map.Entry<String, SSGSession>>(new Comparator<Map.Entry<String, SSGSession>>() {

        @Override
        public int compare(final Map.Entry<String, SSGSession> e1, final Map.Entry<String, SSGSession> e2) {
            return e2.getValue().getStartTime().compareTo(e1.getValue().getStartTime());
        }
    }));

triggers a violation in Sonar, tripping the findbugs rule "SIC_INNER_SHOULD_BE_STATIC_ANON" which has the description: 触发Sonar中的违规行为,绊倒了具有以下描述的findbugs规则“SIC_INNER_SHOULD_BE_STATIC_ANON”:

This class is an inner class, but does not use its embedded reference to the object which created it. 此类是内部类,但不使用其对创建它的对象的嵌入式引用。 This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary. 此引用使类的实例更大,并且可以保持对创建者对象的引用超过必要的时间。 If possible, the class should be made into a static inner class. 如果可能,该类应该成为静态内部类。 Since anonymous inner classes cannot be marked as static, doing this will require refactoring the inner class so that it is a named inner class. 由于匿名内部类不能标记为静态,因此执行此操作将需要重构内部类,以便它是一个命名的内部类。

Really? 真? Isn't this very nit-picky? 这不是很挑剔吗? Should I really refactor a one line method in an anonymous inner class to save the cost of an extra reference ? 我是否应该在匿名内部类中重构一行方法以节省额外引用的成本? In this case, there's no possibility of it holding the reference longer than necessary. 在这种情况下,它不可能长时间保持参考。

I don't mind doing it as our strongly enforced coding standards are "zero sonar violations" but I'm strongly tempted to argue the case for a //NOSONAR here, as imho extracting a one line method to a static inner makes the code slightly harder to grok. 我不介意这样做,因为我们强烈执行的编码标准是“零声纳违规”,但我很想在这里争论一个//NOSONAR的情况,因为imho将一行方法提取到静态内部使得代码稍微难以理解。

What do the java purists think? java纯粹主义者的想法是什么?

Converting comments to answer, first of all I could be persuaded that having this as anonymous inner class can be justified, even if there's a clear technical reason for being nit-picky about this. 将评论转换为答案,首先我可以说服这个作为匿名内部阶级的人可以被证明是合理的,即使有明确的技术理由对此不屑一顾。

Still, I would say: Follow the rules you have set . 不过,我会说: 遵循你设定的规则 Rules create consistency, and when all the code is written the same way, the code base is easier to understand as a whole. 规则创建一致性,当所有代码以相同的方式编写时,代码库作为一个整体更容易理解。 If some rule is bad, disable it everywhere. 如果某些规则不好,请在任何地方禁用它。

When there is an exception, there's also need to explain why there's exception: an extra mental burden for someone reading the code, an extra item to discuss in code review, etc. Only disable rules in individual cases if you can argue it is somehow an exceptional case. 当有异常时,还需要解释为什么会有异常:给读取代码的人带来额外的心理负担,在代码审查中讨论的额外项目等等。如果你认为它是某种情况下,只能在个别情况下禁用规则例外情况。

Also, I'm not sure doing it as static class would be less understandable, even if it adds a bit more boilerplate (and sorry if below is not 100% correct code, my Java is a bit rusty, feel free to suggest edit): 另外,我不确定这样做,因为静态类不太容易理解,即使它添加了更多的样板(如果下面不是100%正确的代码,我的Java有点生疏,随时建议编辑) :

Set<Map.Entry<String, SSGSession>> theSet 
    = new TreeSet<Map.Entry<String, SSGSession>>(new SSGSessionStartTimeComparator());

And then somewhere else in the file, together with other static classes: 然后在文件的其他地方,以及其他静态类:

static class SSGSessionStartTimeComparator extends Comparator<Map.Entry<String, SSGSession>>() {
    @Override
    public int compare(final Map.Entry<String, SSGSession> e1, final Map.Entry<String, SSGSession> e2) {
        return e2.getValue().getStartTime().compareTo(e1.getValue().getStartTime());
    }
}

Just for completeness' sake, I'd like to add another variant to the excellent answers already provided. 为了完整起见,我想为已经提供的优秀答案添加另一个变体。 Define a constant for the Comparator , and use that: Comparator定义一个常量,并使用:

private static final Comparator<Map.Entry<String, SSGSession>> BY_STARTTIME =
        new Comparator<Map.Entry<String, SSGSession>>() {
    @Override
    public int compare(final Map.Entry<String, SSGSession> e1,
            final Map.Entry<String, SSGSession> e2) {
        return e2.getValue().getStartTime().compareTo(e1.getValue().getStartTime());
    }
};

private void foo() {
    Set<Map.Entry<String, SSGSession>> theSet =
        new TreeSet<Map.Entry<String, SSGSession>>(BY_STARTTIME);
}

This saves you the additional class as in hyde's answer . 这可以为你节省额外的课程,就像hyde的答案一样 Otherwise, hyde's answer is better, because it allows you to declare the Comparator to be serializable (which it is, because it has no state). 否则,hyde的答案更好,因为它允许你声明Comparator是可序列化的(它是,因为它没有状态)。 If the Comparator is not serializable, your TreeSet won't be serializable either. 如果Comparator器不可序列化,则TreeSet也不可序列化。

There are three solutions here, the best of which is out of your control: 这里有三种解决方案,其中最好的解决方案是你无法控制的:

  • Extend the Java syntax: 扩展Java语法:

     ... theSet = new static Comparator ... 
  • Declare and use a static class as described. 声明并使用所描述的静态类。

  • Ignore the warning in this one instance: 忽略这个例子中的警告:

     @SuppressFBWarnings("SIC_INNER_SHOULD_BE_STATIC_ANON") ... your method ... 

I prefer the first, but that's a long time coming if ever. 我更喜欢第一个,但是如果有的话,那将是很长一段时间。 Thus I would go for the last before ignoring the rule project-wide. 因此,在忽视项目范围内的规则之前,我会选择最后一个。 Choosing a rule should entail a little pain to override it; 选择一条规则应该有点痛苦来覆盖它; otherwise it's merely a convention or suggestion. 否则它只是一个惯例或建议。

Just a note: anonymous inner classes are great way to leak memory, especially when used in JEE beans. 请注意:匿名内部类是泄漏内存的好方法,尤其是在JEE bean中使用时。 Something as simple: new HashMap<>() {{ put"("a","b"); }}; 简单的事情: new HashMap<>() {{ put"("a","b"); }};

in bean annotated with @javax.ejb.Singleton might lead to multiple instanced being kept alive as that Map keeps reference to bean. 在使用@ javax.ejb.Singleton注释的bean中,可能会导致多个实例保持活动状态,因为Map会保留对bean的引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM