6

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?

Boann
  • 48,794
  • 16
  • 117
  • 146
toddlermenot
  • 1,588
  • 2
  • 17
  • 33
  • 4
    For one, these classes predate enums. But there could very well be other reasons (one being that these objects don't form an enumeration of any kind) – ernest_k Jun 22 '19 at 10:49

3 Answers3

7

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.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • 1
    True. Singleton Pattern is today considered to be an anti-pattern and can be avoided by using dependency injection. – BionicCode Jun 22 '19 at 12:15
  • 1
    Just because it is possible doesn't implicate you should do it. I agree that the intention when introducing `enum` was to provide an enumeration type. That's why they call the type `enum`. To hide a complex class behind an enumeration can't feel good to anyone. I wonder why this idea is propagated. Just because you have to write less code is ridiculous to me. When I see an `enum` I expect an enumeration. My co-worker too. The moment the Java development team or Oracle starts to misuse their own types, using Java would become pain. Even for those who like to implement singletons using `enum`. – BionicCode Jun 22 '19 at 12:25
  • 2
    Expect the unexpected. – BionicCode Jun 22 '19 at 12:25
  • 1
    @BionicCode As you guess I completely agree. I love Joshua Bloch POV at 99% but on this point I never agreed. A meaningful code is essential. We should never need to dig into the implementation of a method to understand its overall intention. With the enum pattern we should do it (to understand the frame of the enum method) and that is an issue. – davidxxx Jun 22 '19 at 12:36
  • Absolutely. You are so right. It's always good to question what you just read. No matter who wrote it. It's good to have a free and powerful mind. I think many people (and Joshua Bloch might be one of them) are intrigued by this particular enum idea, because it looks so clever. And it looks so simple too. Because he's their icon they don't criticize but advocate. Because he has followers (soooo many), he should act more responsible. Rather trying to convince people to leave singletons alone instead of teaching how to hack them into an enumeration. – BionicCode Jun 22 '19 at 13:09
  • He said "APIs should be easy to use and hard to misuse." Many argue that the Java `enum` is more powerful than e.g. the C# `enum` (because "you can't do that in C#"). But according to his own statement he should've come to the conclusion, that Java's `enum` type was badly designed, since it allows you to do this fancy stuff with it. – BionicCode Jun 22 '19 at 13:09
  • I take a different view, though I accept I am in the minority. To the best of my knowledge `Enum` elements are each compiled as a `Class`. As such I fully expect an `Enum` to behave like a class (sub-classing rules not withstanding). To my mind this makes `Enum` extremely well designed, I might consider them to be slightly miss-named, if I squint a bit perhaps `Sum` or some other variant would be a better name. Also as classes I question why we define them using the convention for constants. :) – Gavin Jun 22 '19 at 15:20
  • @BionicCode the keywords were "might" and "consider". `Enum` is an enumeration of classes. The choice of "Sum" was that it looks to me a little like a `Sum` type, though given `Enum`s restrictions only in a limited manner. And just to bring it back to `Enum`s with a single constant; if you where to enumerate the natural satellites of Earth or perhaps the the stars in our solar system how many would you get? – Gavin Jun 23 '19 at 09:21
  • @BionicCode If the Java guys wanted `Enum` to be a simple enumeration why did they give `Enum` many class like attributes and restrict others. Neither I nor you can answer this question, we live with and use what they did design, I chose to think of `Enum` as powerful and well designed. – Gavin Jun 23 '19 at 09:27
  • @Gavin Why would you create an enumeration with only one variable? If it's one variable then it must be a class? So this makes `MOON` a singleton? Where is this common rule defined? My point is not about a single enumeration constant (if this makes sense to you). It's about the shock in my face when this _constant_ of your API turns out to be a _database connector_ (as this example of a singleton is often found in the polluted www)! I don't want to convince you. Your arguments can't explain why it is a brilliant act to misuse enumeration types. And I thank God that Oracle doesn't follow you. – BionicCode Jun 23 '19 at 09:46
5

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.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • I assumed `Desktop` would have to fit into an old library/api so it would have increased workload... but at the end of the day only the designers know :) – Gavin Jun 22 '19 at 10:57
  • 3
    My guess why even the Java team seems to avoid 'misusing' the `enum` type, is that `enum` was designed with different intention in mind: enumerations (hence the name _enum_). Oracle: "An enum type is a special data type that enables for a variable to be a set of predefined constants.". This is what everybody expects when he sees an `enum` - an enumeration variable. Nobody would expect a complex class behind it. I think it's just consequent not to use `enum` for something else. Imaging a library with plenty of `enum` types and you don't know whether they are classes or just plain enumeration. – BionicCode Jun 22 '19 at 11:57
  • That is certainly a high probability. However once a language feature or API is released into the wild you no longer have control over it, it will be used in ways in you can not expect. This isnt the first time the Java community has found an unexpected way to (ab)use a language feature or API, nor the last. – Gavin Jun 22 '19 at 15:26
1

There could be a great number of reasons. Enum was released in Java 1.5 so Runtime certainly predates that and to change it to an Enum would likely break existing code, and Java doesnt like to break existing code (generics is a big example of the hoops we have to jump through to maintain backwards compatibility).

For new classes like Desktop that have to fit into an old API you could also site backwards compatibility.

I personally think Enum are very useful and I tend to treat them (in my personal projects) just like any other class (subject to their unique restrictions).

Gavin
  • 1,725
  • 21
  • 34