1

I am creating a Comparator as Anonymous inner class and I am not sure if its the best approach. I am creating it only once in my code, but what I am not sure is whether that inner class is created each time I am sorting a list. For example in an application if I am calling the sort method using that comparator 10 times, would there be ten extra classes created?

Collections.sort(originalList, new Comparator<User>() {
    @Override
    public int compare(User o1, User o2) {
        int value1 = o1.getPropertyCode().compareTo(o2.getPropertyCode());
        if (value1 == 0) {
            int value2=o1.getPropertyValue().compareTo(o2.getPropertyValue());
            return value2;
        }
        return value1;
    }
});

vs

Collections.sort(originalList, new SomeComparator());

javaAndBeyond
  • 520
  • 1
  • 9
  • 26

2 Answers2

3

Anonymous classes are turned into a regular class definition by the compiler and are actually given a name like OutterClass$1, you can not refer to that class by that name but you can do for example new Object() {}.class.getName() to see that it's always the same. Whenever your code hits the line in question it's using just 1 class - whether you give it an explicit name or not. Your 2 options are basically the same.

But when you read your line of code up until Collections.sort(originalList, new you should be aware that that new creates a new instance (not a class) every time. I.e. it allocates memory, initializes the thing, .. none of which is needed more than once because the created comparator object will never differ.

What you'll want to do is either storing the created comparator once in a field like so (or like in Java's own source String.CASE_INSENSITIVE_ORDER)

private static final Comparator<User> USER_COMPARATOR = new Comparator<User>() {
    @Override
    public int compare(User o1, User o2) {
        int value1 = o1.getPropertyCode().compareTo(o2.getPropertyCode());
        if (value1 == 0) {
            int value2=o1.getPropertyValue().compareTo(o2.getPropertyValue());
            return value2;
        }
        return value1;
    }
};
private void someCode() {
    Collections.sort(originalList, USER_COMPARATOR);
}

Or with Java 8 you can turn it into a lambda (notice the missing new) which also doesn't create new instances every time

Collections.sort(originalList, (o1, o2) -> {
    int value1 = o1.getPropertyCode().compareTo(o2.getPropertyCode());
    if (value1 == 0) {
        int value2=o1.getPropertyValue().compareTo(o2.getPropertyValue());
        return value2;
    }
    return value1;
});
zapl
  • 63,179
  • 10
  • 123
  • 154
  • If you're turning it into a lambda, you might as well write the much more compact `comparing(User::getPropertyCode).thenComparing(User::getPropertyValue)`. – Louis Wasserman May 02 '16 at 21:13
  • Excellent, did not know about this being used in String class. This should be made more popular, like a design pattern. Not that memory is always a problem with extra classes, but I am sure its helpful in my case. – javaAndBeyond May 02 '16 at 21:14
  • @LouisWasserman downside is that this doesn't result in a static-field like lambda but one that gets generated each time that code runs. Probably not after JIT gets its hand on it.. but anyways I'd assign it to a static field in that case – zapl May 02 '16 at 21:18
0

It depends. If you have that Comparator in a method, then at each call a new one will be instantiated. Moreover, that Comparator will contain a reference to the encompassing class.

On the other hand, if you define that anonymous inner class as a static field, then there will be only one (per class loader).

Tamas Rev
  • 7,008
  • 5
  • 32
  • 49