Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the core Java library NOT use enums for implementing the singleton pattern? [closed]

The core Java classes pointed to by the famous BalusC answer (https://stackoverflow.com/a/2707195):

java.lang.Runtime#getRuntime()
java.awt.Desktop#getDesktop()
java.lang.System#getSecurityManager()

All the above seem to be classes with private constructors instead of being enums. If enum is the best practice to implement a singleton pattern (Why is Enum best implementation for Singleton), why was it not used in the core Java source?

like image 728
toddlermenot Avatar asked Jun 22 '19 10:06

toddlermenot


2 Answers

Semantic behind enums

I don't think that we should see Java enums as the unique way to create one and only one instance of a class whatever the Java version.
Enums convey a meaning: a set of enumerated values defined for a specific entity.
Using it as a singleton that performs inside it a lot of logic (remote calls, persistence and so forth...) is not something that I encourage.
Semantically the readers of the code don't expect such logic inside it when an enum is used in some code.

The Bill Pugg idiom used here with an eager initialization is a fair alternative to enum, for example in Runtime class :

private static Runtime currentRuntime = new Runtime();
private Runtime() {}

Singleton implementations in the JDK 5 (version where the enum feature appeared) or later source code

I have much more frequently find singleton implementations without the enum pattern than with it.

Some examples of singleton class without enum usage :

Desktop(JDK 6) .

public static synchronized Desktop getDesktop(){
   //...
   Desktop desktop = (Desktop)context.get(Desktop.class);
    if (desktop == null) {
        desktop = new Desktop();
        context.put(Desktop.class, desktop);
    }
  //...
}

Don't pull conclusions only from that case since that is a special case with a lazy initialization .

Collections (JDK 1.7) :

/**
 * Returns an enumeration that has no elements.  More precisely,
 *
  ...
 * @since 1.7
 */
@SuppressWarnings("unchecked")
public static <T> Enumeration<T> emptyEnumeration() {
    return (Enumeration<T>) EmptyEnumeration.EMPTY_ENUMERATION;
}

private static class EmptyEnumeration<E> implements Enumeration<E> {
    static final EmptyEnumeration<Object> EMPTY_ENUMERATION
        = new EmptyEnumeration<>();

    public boolean hasMoreElements() { return false; }
    public E nextElement() { throw new NoSuchElementException(); }
    public Iterator<E> asIterator() { return emptyIterator(); }
}

IsoChronology(JDK 8) :

public final class IsoChronology extends AbstractChronology implements Serializable {

    /**
     * Singleton instance of the ISO chronology.
     */
    public static final IsoChronology INSTANCE = new IsoChronology();
}

OptionalIntDeserializer(JDK 8) :

public class OptionalIntDeserializer extends BaseScalarOptionalDeserializer<OptionalInt>
{
    private static final long serialVersionUID = 1L;

    static final OptionalIntDeserializer INSTANCE = new OptionalIntDeserializer();

}

And less frequently you can find singleton(s) implemented with the enum pattern.

Comparators (JDK 1.8) :

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 leave you pulling conclusions from these examples.

Coding a singleton : often an anti-pattern

To go further, the singleton is an anti-pattern when that is implemented by hard coding it explicitly: you can avoid it with enums like with the old-fashioned way (static eager or lazy singleton) by introducing an interface that it implements and a factory method to retrieve it.

But finally all that requires constant rigor (so is error prone) and favors boilerplate code (so makes your code less meaningful than it could be).
Dependency injection solves this issue. So I think that the best way to create a singleton is finally to not explicitly create singletons.

like image 160
davidxxx Avatar answered Sep 30 '22 23:09

davidxxx


Because they don't have a time machine.

enums were introduced in Java 5 "Tiger" in 2004. java.lang.runtime.Runtime#getRuntime() was introduced in Java 1.0 in 1996. java.lang.runtime.System#getSecurityManager() was introduced in Java 1.0 in 1996.

java.awt.Desktop#getDesktop() was introduced in Java 6 "Mustang" in 2006, so it could theoretically have used enums. You'll have to ask the designers why they chose this particular design.

like image 35
Jörg W Mittag Avatar answered Oct 01 '22 01:10

Jörg W Mittag