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?
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).
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.
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.
A normal class can implement any number of interfaces but the anonymous inner class can implement only one interface at a time.
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());
}
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With