Bugs: One good thing about them is they keep on inspiring even when you don't want to be.

Sunday, April 12, 2015

Overview of Enum in Java

As per the doc "An enum 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. " There are various examples for it:

Where should I use an Enum?
When a variable can take one of the values from a small set of predefined values then using an Enum may make sense. One classical example of using enum is writing thread-safe singleton as mentioned in Effective Java.

What is an EnumSet?
If we use enums and want to allows a set of values then we should use EnumSet but all the values must come from a single enum that is specified when the set is created.

Why should I prefer an Enum?
Suppose in the above example we are passing the OS in string form:

Now user can pass even an operation system for which product has no installation support, worse (s)he can pass any random string. So using an Enum provides

provides type safety and better compile time error checking.

passing an enum as parameter makes it self-documented in sense that one of the possible values from that enum can only be passed.

also avoid errors in passing invalid constants. We can also document legal use cases to use with this enum.

By using an enum we can print more sensible value if we override toSring method in it.

also helpful in case of auto completion when using an IDE e.g. IntelliJ IDEA.

when we create an enum compiler also adds some helpful methods e.g. values that returns an array containing all of the values of the enum in the order they are declared.

Why an enum cannot extend anything else?
Because all enums explicitly extend java.lang.enum and a class can only extend one class in Java.

How enum differs from class?
Enum is similar to a regular class but it always has private constructor. We also get some additional supporting methods like values, valueof etc. Also intent with an enum is different from a class as we want to have fixed number of instances in case of an enum but not in case of a class.

Are fields of an enum implicitly final?
No they are not. Consider the following example:

The output would be:Version of PRODUCT_ONE: 1.1PRODUCT_ONEVersion of PRODUCT_ONE: 1.3PRODUCT_ONE

Generally we would not create mutable enums but some examples are still there e.g. lazy initialization (when we need to compute some field value when they are first used), a regular singleton object e.g. Registry etc. In most cases enum objects would be immutable and their fields be final. We can also use reflection to examine enum.

Why an enum cannot have public or protected constructor?
An enum must have package-private or private access constructor. We can think Enum as a class with fixed number of instances and the number is not going to change at run time. We provide public or protected constructors when we allow more instances to be created and now it seems to make sense that we do not need public or protected constructors. An enum automatically creates the constants at the beginning of enum body and we cannot invoke an enum constructor our-self.

Can we declare an Enum inside a method?
An enum can be declared inside or outside of a class but not in a method.As per the doc:Nested enum types are implicitly static. It is permissible to explicitly declare a nested enum type to be static. This implies that it is impossible to define a local enum, or to define an enum in an inner class.Can we mark an Enum final?
As mentioned above all nested enums are implicitly static. But we cannot mark an enum declared outside of a class as any of the following: static, abstract, final, protected or private.

How can we ensure that all enum values are used?
In one of the projects we are using Enum to specify appliance type which can have various possible values e.g. Red Hat Linux, SUSE, Windows etc.

Now everything is fine till here. Now after some time a new appliance gets introduced e.g. Ubuntu appliance and now we need to scan the code to introduce code for this new kind of appliance. This feels like code smell and needs to be handled. The objective is to ensure that every enum value is used.

The point to observe is every enum should have processing method so we can introduce an abstract method in enum itself and next thing is to ensure that every enum value will provide implementation for that method.

Now next time we introduce a new appliance type that must also implement the abstract method else it will not compile. Another option is to declare an interface and make sure the enum implements this interface.