Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton of Java functional interface as enum

While looking at the source code of the Comparators class, I came across these lines of code.

class Comparators {

    //...

    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
        INSTANCE;

        @Override
        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
            return c1.compareTo(c2);
        }

        @Override
        public Comparator<Comparable<Object>> reversed() {
            return Comparator.reverseOrder();
        }
    }

    //...

}

I think I understand what this does. It's a Singleton instance which implements the Comparator interface. It uses the "compareTo" of classes that implement the Comparable interface for natural ordering (please correct me if I am wrong in any of this).

What I do not understand however, why is it done using an enum. I really like enums for Singletons, don't get me wrong but in this case I personally think this would have been simpler:

public static final Comparator<Comparable<Object>> NATURAL_ORDER_COMPARATOR =
    new Comparator<Comparable<Object>>() {
        @Override
        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
            return c1.compareTo(c2);
        }

        //...

    }

Are there any reasons to implement this using enums aside from personal preference?

like image 670
Yeater Avatar asked Jul 12 '18 06:07

Yeater


2 Answers

It maybe due to Serializable.

Based on your approach, if you create an object that holds the Comparators.NATURAL_ORDER_COMPARATOR, when you write to the object and read it back, a new NATURAL_ORDER_COMPARATOR will be created. Since the object cost is so small it breaks the singleton.

Some evidence for that is Collections.ReverseComparator. It uses your approach:

static final ReverseComparator REVERSE_ORDER = new ReverseComparator();

But the drawback is that the following code must be present to maintain the singleton

private Object readResolve() { return Collections.reverseOrder(); }

Now which one is easier? Personally, I prefer to use 'enum singleton' pattern as my first choice.

like image 77
Dean Xu Avatar answered Sep 30 '22 00:09

Dean Xu


That is exactly the point in Item 89: For instance control, prefer enum types to readResolve from Effective Java actually and it has to do with Serialization.

Maintaining readResolve instead of the enum instance is much more complicated and cumbersome.

like image 33
Eugene Avatar answered Sep 30 '22 00:09

Eugene