Синглтон функционального интерфейса Java как перечисление

Рассматривая исходный код класса Comparators, я натолкнулся на эти строки кода.

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();
        }
    }

    //...

}

Я думаю, я понимаю, что это делает. Это экземпляр Singleton, который реализует интерфейс Comparator. Он использует "compareTo" классов, которые реализуют интерфейс Comparable для естественного упорядочения (пожалуйста, поправьте меня, если я ошибаюсь в этом).

Однако я не понимаю, почему это делается с использованием перечисления. Мне очень нравятся перечисления для Singletons, не поймите меня неправильно, но в этом случае я лично думаю, что это было бы проще:

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);
        }

        //...

    }

Есть ли какие-либо причины для этого, используя перечисления, помимо личных предпочтений?

Ответ 1

Возможно, из-за Serializable.

На основе вашего подхода, если вы создадите объект, который содержит Comparators.NATURAL_ORDER_COMPARATOR, когда вы пишете объект и читаете его, будет создан новый NATURAL_ORDER_COMPARATOR. Поскольку стоимость объекта настолько мала, что он обрывает синглтон.

Некоторыми доказательствами для этого являются Collections.ReverseComparator. Он использует ваш подход:

static final ReverseComparator REVERSE_ORDER = new ReverseComparator();

Но недостатком является то, что для поддержания синглтона должен присутствовать следующий код

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

Теперь, какой из них проще? Лично я предпочитаю использовать шаблон "enum singleton" в качестве своего первого выбора.

Ответ 2

Это точно так же, как в пункте 89: например, управление, предпочитайте типы перечислений для чтенияResolve из Effective Java на самом деле и это связано с Serialization.

Поддержание readResolve вместо экземпляра enum намного сложнее и громоздко.