EnumSet in Java is
a special implementation of Set interface added back in Java 1.5, when
Enum was first introduced into the Java Programming language.
Surprisingly so many years after the Java 1.5 release (released
30th September 2004, codenamed Tiger), a lot of Java programmers
are still unaware of several good features that were
introduced. EnumSet is one of such example which can be really
useful and provides greater performance when compared to
other Set implementations for Enum constants. When I
discussed
EnumMap in Java on my blog I wanted to mention
EnumSet as well, but couldn't find the time.
However, reading a recent Interview question about
How EnumSet is implemented
in Java from one of
my readers triggered this post. Indeed, EnumSet is becoming popular
in Java interviews because of its high performance and specialized
use with Enum constants. In this Java tutorial, we will talk about
what EnumSet means for Java, how it's implemented in the form
of RegularEnumSet and JumboEnumSet and most importantly when to use EnumSet in
Java.
What is EnumSet
As mentioned previously, it's a special
implementation of Set interface, which means you can pass it to a
method, which accepts Set interface as a parameter.
EnumSet
can only be used with Enum constants,
which means you can not store any other object in EnumSet. EnumSet
also presents a good example of the
Factory method design pattern to create
instances.
It enforces the
use of Factory method by declaring EnumSet as an
abstract classand making its concrete implementation
RegularEnumSet and
JumboEnumSet package-private.
This means you can neither create an instance of EnumSet nor any of
its implementations. This kind of of enforcement is good, if you
provide different Factory methods for different needs. EnumSet is right on
the money there as you can see methods like EnumSet.of(E...),
which creates EnumSet of elements
provided to it.
This is an excellent use of
method
overloading and
variable
arguments. EnumSet.of() method is overloaded for common usage, which
tends to perform better than variable argument version, and can be
added for flexibility to create enum with any number of instances.
Additionally EnumSet provides methods like copyOf(), noneOf() to create EnumSet by copying elements from other collections,
and creating empty EnumSet of a particular Enum type in
Java.
How EnumSet is implemented in Java
EnumSet is an
abstract class and it provides two concrete implementations,
java.util.RegularEnumSet
and java.util.JumboEnumSet.
The main difference between the two is that the former uses a
long
variable to store elements while later uses a long[] to store its
element. Since RegularEnumSet uses
long variable, which is a 64 bit data type, it can only hold that
much of an element. That's why when an empty EnumSet is created
using EnumSet.noneOf()method.
It chooses RegularEnumSet if
the key universe (number of enum instances in Key Enum) is less
than or equal to 64. It chooses JumboEnumSet if the
key universe is more than 64. Here is the code which does that
:
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) { .. ............ if (universe.length <= 64) return new RegularEnumSet<E>(elementType, universe); else return new JumboEnumSet<E>(elementType, universe); }
Though this is a
pretty low level implementation in detail, it's always good to know
about it to impress in an job interview if you were asked the
question.
When to use EnumSet in Java
Joshua Bloch has
mentioned an interesting use case scenario for EnumSet in Item 32 of his Java Classic
Effective Java. This item advises us to use
EnumSet in the place of bit fields, which is part of
enum int pattern. In enum int pattern, different enum constants are represented
as power of 2 and later combined using
bitwise
operators. I strongly suggest looking that example
mentioned in the book; it's very clear and quite useful as well.
Now back to general usage - whenever you need to group certain
enums for a meaningful purpose, you can use EnumSet e.g. if you have an
enum to represent DayOfWeek, you can use EnumSet to create WEEKDAYS and WEEKEND, instead of defining separate enum for that
example. So,
private enum DayOfWeek{ MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; } private EnumSet weekend = EnumSet.of(SATURDAY,SUNDAY);
Similarly, months of year can be logically
grouped into different seasons e.g. Summer,
Winter
as shown below
:
enum Month{ JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER; } EnumSet summer = EnumSet.of(Month.MARCH, Month.APRIL, Month.MAY, Month.JUNE); EnumSet winter = EnumSet.of(Month.OCTOBER, Month.NOVEMBER, Month.DECEMBER, Month.JANUARY);
So, apart from using EnumSet in the
place of enum
int pattern, you can also use it to a create logical
grouping of different instances of a single enum type.
Important points about EnumSet
Here are some worthwhile things to know
about EnumSet in Java. Like all other collection classes, I
strongly recommend getting familiar with the specifics of
EnumSet
before using it in
production code.
- EnumSet can only be created of a single enum type, which means you can not create EnumSet of Month and DayOfWeek together.
- EnumSet doesn't allow null elements. Attempting to insert null on EnumSet will throw NullPointerException.
- EnumSet is not thread-safe, which means if it needs to be externally synchronized, when multiple threads access it and one of them modifies the collection.
- Iterator of EnumSet is fail-safe and weakly consistent, which means no ConcurrentModificationException. Also traversing order of Iterator is defined by natural ordering of Enum, and it may or may not show result of any modification done during iteration.
- EnumSet is a high performance Java Collection. It provides O(1) performance for add(), contains() and next() operations because of array based access. Preferably, use EnumSet over HashSet for storing Enum constants.
Thanks for your
time guys, I hope you could take as much advantage of EnumSet as
possible. You should also read
Effective Java and its item on EnumSet to learn
about the enum int pattern and how EnumSet is a good alternative to
it.
No comments:
Post a Comment