Today I was browsing through some questions on this site and I found a mention of an enum
being used in singleton pattern about purported thread safety benefits
Why use any programming language feature? The reason we have languages at all is for
Enums improve both likelihood of correctness and readability without writing a lot of boilerplate. If you are willing to write boilerplate, then you can "simulate" enums:
public class Color {
private Color() {} // Prevent others from making colors.
public static final Color RED = new Color();
public static final Color AMBER = new Color();
public static final Color GREEN = new Color();
}
Now you can write:
Color trafficLightColor = Color.RED;
The boilerplate above has much the same effect as
public enum Color { RED, AMBER, GREEN };
Both provide the same level of checking help from the compiler. Boilerplate is just more typing. But saving a lot of typing makes the programmer more efficient (see 1), so it's a worthwhile feature.
It's worthwhile for at least one more reason, too:
Switch statements
One thing that the static final
enum simulation above does not give you is nice switch
cases. For enum types, the Java switch uses the type of its variable to infer the scope of enum cases, so for the enum Color
above you merely need to say:
Color color = ... ;
switch (color) {
case RED:
...
break;
}
Note it's not Color.RED
in the cases. If you don't use enum, the only way to use named quantities with switch
is something like:
public Class Color {
public static final int RED = 0;
public static final int AMBER = 1;
public static final int GREEN = 2;
}
But now a variable to hold a color must have type int
. The nice compiler checking of the enum and the static final
simulation is gone. Not happy.
A compromise is to use a scalar-valued member in the simulation:
public class Color {
public static final int RED_TAG = 1;
public static final int AMBER_TAG = 2;
public static final int GREEN_TAG = 3;
public final int tag;
private Color(int tag) { this.tag = tag; }
public static final Color RED = new Color(RED_TAG);
public static final Color AMBER = new Color(AMBER_TAG);
public static final Color GREEN = new Color(GREEN_TAG);
}
Now:
Color color = ... ;
switch (color.tag) {
case Color.RED_TAG:
...
break;
}
But note, even more boilerplate!
Using an enum as a singleton
From the boilerplate above you can see why an enum provides a way to implement a singleton. Instead of writing:
public class SingletonClass {
public static final void INSTANCE = new SingletonClass();
private SingletonClass() {}
// all the methods and instance data for the class here
}
and then accessing it with
SingletonClass.INSTANCE
we can just say
public enum SingletonClass {
INSTANCE;
// all the methods and instance data for the class here
}
which gives us the same thing. We can get away with this because Java enums are implemented as full classes with only a little syntactic sugar sprinkled over the top. This is again less boilerplate, but it's non-obvious unless the idiom is familiar to you. I also dislike the fact that you get the various enum functions even though they don't make much sense for the singleton: ord
and values
, etc. (There's actually a trickier simulation where Color extends Integer
that will work with switch, but it's so tricky that it even more clearly shows why enum
is a better idea.)
Thread safety
Thread safety is a potential problem only when singletons are created lazily with no locking.
public class SingletonClass {
private static SingletonClass INSTANCE;
private SingletonClass() {}
public SingletonClass getInstance() {
if (INSTANCE == null) INSTANCE = new SingletonClass();
return INSTANCE;
}
// all the methods and instance data for the class here
}
If many threads call getInstance
simultaneously while INSTANCE
is still null, any number of instances can be created. This is bad. The only solution is to add synchronized
access to protect the variable INSTANCE
.
However, the static final
code above does not have this problem. It creates the instance eagerly at class load time. Class loading is synchronized.
The enum
singleton is effectively lazy because it's not initialized until first use. Java initialization is also synchronized, so multiple threads can't initialize more than one instance of INSTANCE
. You're getting a lazily initialized singleton with very little code. The only negative is the the rather obscure syntax. You need to know the idiom or thoroughly understand how class loading and initialization work to know what's happening.
There are many answers here, just want to point two specific ones:
1) Using as constants in Switch-case
statement.
Switch case won't allow you to use String objects for case. Enums come in handy. More: http://www.javabeat.net/2009/02/how-to-use-enum-in-switch/
2) Implementing Singleton Design Pattern
- Enum again, comes to rescue. Usage, here: What is the best approach for using an Enum as a singleton in Java?
Enum? Why should it be used? I think it's more understood when you will use it. I have the same experience.
Say you have a create, delete, edit and read database operation.
Now if you create an enum as an operation:
public enum operation {
create("1")
delete("2")
edit("3")
read("4")
// You may have is methods here
public boolean isCreate() {
return this.equals(create);
}
// More methods like the above can be written
}
Now, you may declare something like:
private operation currentOperation;
// And assign the value for it
currentOperation = operation.create
So you can use it in many ways. It's always good to have enum for specific things as the database operation in the above example can be controlled by checking the currentOperation. Perhaps one can say this can be accomplished with variables and integer values too. But I believe Enum is a safer and a programmer's way.
Another thing: I think every programmer loves boolean, don't we? Because it can store only two values, two specific values. So Enum can be thought of as having the same type of facilities where a user will define how many and what type of value it will store, just in a slightly different way. :)