Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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.

What do the java purists think?

like image 571
Steve Atkinson Avatar asked Feb 24 '14 18:02

Steve Atkinson


People also ask

Which sentence is true about anonymous inner class?

Explanation: Option C is correct because the syntax of an anonymous inner class allows for only one named type after the new, and that type must be either a single interface (in which case the anonymous class implements that one interface) or a single class (in which case the anonymous class extends that one class).

What is anonymous inner class?

Java anonymous inner class is an inner class without a name and for which only a single object is created. An anonymous inner class can be useful when making an instance of an object with certain "extras" such as overloading methods of a class or interface, without having to actually subclass a class.

Can inner class instantiate anonymously?

Anonymous classes are inner classes with no name. Since they have no name, we can't use them in order to create instances of anonymous classes. As a result, we have to declare and instantiate anonymous classes in a single expression at the point of use. We may either extend an existing class or implement an interface.

How many objects can an anonymous inner class make?

A normal class can implement any number of interfaces but the anonymous inner class can implement only one interface at a time.


3 Answers

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):

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());
    }
}
like image 161
hyde Avatar answered Nov 14 '22 15:11

hyde


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:

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. 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). If the Comparator is not serializable, your TreeSet won't be serializable either.

like image 32
barfuin Avatar answered Nov 14 '22 13:11

barfuin


There are three solutions here, the best of which is out of your control:

  • Extend the Java syntax:

    ... 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.

like image 1
David Harkness Avatar answered Nov 14 '22 14:11

David Harkness