Demystifying Java Enums
Let’s nally understand them
Akshita Chawla | 14th Oct 2023
fi
What are we covering today?
• ABCs of Enum
• Enums under the hood
• When to use Enums?
• Use enums instead of int constant
• Use instance elds instead of ordinals
• Use EnumMap instead of ordinal indexing
• Implement Design Patterns Using Enums
• Singleton Pattern
• Strategy Pattern
© Akshita Chawla
fi
A..B..C..s of Enum
An Enumerations—or “enums” for short type , is a special data type that enables for a variable to be a set of predefined constants.
The variable must be equal to one of the values that have been predefined for it.
To associate data with enum constants, declare instance
Enums are by their nature immutable, so all elds should be nal
Declaration of Enum
Enums values can have
Enums can have
constructor
Enums can have
methods
© Akshita Chawla
fi
fi
fi
Enums :
What you see vs What JVM sees
What you see What Compiler sees
© Akshita Chawla
Enum : Under the Hood
Every enum constant is a reference
variable to that enum type Object.
Internally enum’s are implemented
by using the class concept.
Every enum constant is
implicitly public static
© Akshita Chawla
fi
© Akshita Chawla
When to use enums ? Use Enums instead of int constants
Before enum types were added to the language, a common pattern for
representing enumerated types was to declare a group of named int constants,
one for each member of the type
int enum pattern
Programs that use int enums are brittle. Because int enums are
constant variables, their int values are compiled into the clients that
use them.If the value associated with an int enum is changed, its
clients must be recompiled. If not, the clients will still run, but their
behavior will be incorrect.
The String enum pattern variant is even less desirable.
While it does provide printable strings for its constants, it can lead naive users to hard-code string constants into client
code instead of using eld names.
If such a hard-coded string constant contains a typographical error, it will escape detection at compile time and result in
bugs at runtime.
© Akshita Chawla
fi
When to use enums ? Use Enums instead of int constants
Type Instance
Safe Controlled
Enums provide compile-time type safety. If you declare a parameter
Enum types are effectively to be of type Apple, you are guaranteed that any non-null object
reference passed to the parameter is one of the three valid Apple
values. Attempts to pass values of the wrong type will result in
compile-time errors, as will attempts to assign an expression of one
Instance enum type to a variable of another, or to use the == operator to
Controlled compare values of di Type
Safe
© Akshita Chawla
ff
fi
When to use enums ? Use Enums instead of int constants
Sometimes you need to associate fundamentally different behavior with each constant
Better way to do it
If you add a new constant to the second version of
Operation, it is unlikely that you’ll forget to provide an apply
This code works, but it isn’t very pretty. It won’t compile method, because the method immediately follows each
without the throw statement because the end of the method constant declaration. In the unlikely event that you do forget,
is technically reachable, even though it will never be reached. the compiler will remind you because abstract methods in an
Worse, the code is fragile. If you add a new enum constant enum type must be overridden with concrete methods in all
but forget to add a corresponding case to the switch, the of its constants.
enum will still compile, but it will fail at runtime when you try
to apply the new operation.
© Akshita Chawla
When to use enums ? Use instance fields instead of ordinals
Many enums are naturally associated with a single int value. All enums have an ordinal method, which
returns the numerical position of each enum constant in its type.
Better way to do it
While this enum works, it is a
maintenance nightmare. If the
constants are reordered, the Never derive a value associated
numberOfMusicians method will with an enum from its ordinal;
break. store it in an instance eld instead
Note The Enum speci cation has this to say about ordinal: “Most
programmers will have no use for this method. It is designed for
use by general-purpose enum- based data structures such as
EnumSet and EnumMap.” © Akshita Chawla
fi
fi
When to use enums ? Use EnumMap instead of ordinal indexing
This technique works, but it is fraught with problems. Because
arrays are not compatible with generics , the program requires
an unchecked cast and will not compile cleanly. Because the
array does not know what its index represents, you have to
label the output manually. But the most serious problem with
this technique is that when you access an array that is indexed
by an enum’s ordinal, it is your responsibility to use the correct
int value; ints do not provide the type safety of enums. If you
use the wrong value, the program will silently do the wrong
thing or—if you’re lucky—throw an
ArrayIndexOutOfBoundsException.
Class De nition
Better way to do it
EnumMap Approach
This program is shorter, clearer, safer, and comparable in speed to the original version. There is
no unsafe cast; no need to label the output manually because the map keys are enums that
know how to translate themselves to printable strings; and no possibility for error in computing
Using Ordinal Indexing Approach array indices. The reason that EnumMap is comparable in speed to an ordinal-indexed array is
that EnumMap uses such an array internally, but it hides this implementation detail from the
programmer, combining the richness and type safety of a Map with the speed of an array.
© Akshita Chawla
fi
Implement Design Patterns Using Enums
Let’s take a look how we can
use Enums in our everyday
design patterns
© Akshita Chawla
Singleton Pattern
Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance
Traditional methods of making singletons
Singleton with public static factory method
Singleton with public static nal eld
Not safe
with deserialization. Not safe
with deserialization.
Singleton with lazy initialization
All of the above methods works
Let’s think again how did we achieve the singleton behavior in above methods. It was done
by making the constructor private and making inaccessible the constructor to create new
instances of the class.
But the problem is, actually isn’t there any other ways to create an instance of a class other
than the constructor? Answer is no.
There are some other advance methods.
THREAD
• Serialization and deserialization
Not safe
SAFE • Re
with deserialization. © Akshita Chawla
fl
fi
fi
Singleton Pattern
Since enums are inherently serializable we don’t need to implement it with serializable interface. Re ection
problem is also not there. Therefore, it is 100% guaranteed that only one instance of the singleton is
present within a JVM.
Conventional Singletons is that they are no longer Singleton once you implement a serializable
interface because the method readObject() always returns a new instance just like the Java
constructor. By using the readResolve() method and discarding newly created instances, you can
avoid that by substituting Singleton
THREAD By default, the Enum instance is thread-safe, and you don’t need
SAFE to worry about double-checked locking.
Safe with
deserialization.
One thing to remember here is when serializing an enum, eld variables are not
get serialized. For example, if we serialize and deserialize above SingletonEnum
class, we will loss the value of the int value eld
Note
© Akshita Chawla
fi
fi
fl
Strategy Pattern
The Strategy Pattern de
This pattern allow us to apply an important concept of
object oriented programming: favor composition over
inheritance, which we can translate as the ability to
change an object’s behavior on runtime.
Traditional
Implementation Enum Implementation
© Akshita Chawla
fi
© Akshita Chawla