[java] What's the advantage of a Java enum versus a class with public static final fields?

I am very familiar with C# but starting to work more in Java. I expected to learn that enums in Java were basically equivalent to those in C# but apparently this is not the case. Initially I was excited to learn that Java enums could contain multiple pieces of data which seems very advantageous (http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html). However, since then I have found a lot of features missing that are trivial in C#, such as the ability to easily assign an enum element a certain value, and consequently the ability to convert an integer to an enum without a decent amount of effort (i.e. Convert integer value to matching Java Enum).

So my question is this: is there any benefit to Java enums over a class with a bunch of public static final fields? Or does it just provide more compact syntax?

EDIT: Let me be more clear. What is the benefit of Java enums over a class with a bunch of public static final fields of the same type? For example, in the planets example at the first link, what is the advantage of an enum over a class with these public constants:

public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);

As far as I can tell, casablanca's answer is the only one that satisfies this.

This question is related to java enums

The answer is


  1. Type safety and value safety.
  2. Guaranteed singleton.
  3. Ability to define and override methods.
  4. Ability to use values in switch statement case statements without qualification.
  5. Built-in sequentialization of values via ordinal().
  6. Serialization by name not by value, which offers a degree of future-proofing.
  7. EnumSet and EnumMap classes.

There is less confusion. Take Font for instance. It has a constructor that takes the name of the Font you want, its size and its style (new Font(String, int, int)). To this day I cannot remember if style or size goes first. If Font had used an enum for all of its different styles (PLAIN, BOLD, ITALIC, BOLD_ITALIC), its constructor would look like Font(String, Style, int), preventing any confusion. Unfortunately, enums weren't around when the Font class was created, and since Java has to maintain reverse compatibility, we will always be plagued by this ambiguity.

Of course, this is just an argument for using an enum instead of public static final constants. Enums are also perfect for singletons and implementing default behavior while allowing for later customization (I.E. the strategy pattern). An example of the latter is java.nio.file's OpenOption and StandardOpenOption: if a developer wanted to create his own non-standard OpenOption, he could.


Another important difference is that java compiler treats static final fields of primitive types and String as literals. It means these constants become inline. It's similar to C/C++ #define preprocessor. See this SO question. This is not the case with enums.


The biggest advantage is enum Singletons are easy to write and thread-safe :

public enum EasySingleton{
    INSTANCE;
}

and

/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;

     private DoubleCheckedLockingSingleton(){}

     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

both are similar and it handled Serialization by themselves by implementing

//readResolve to prevent another instance of Singleton
    private Object readResolve(){
        return INSTANCE;
    }

more


The primary advantage is type safety. With a set of constants, any value of the same intrinsic type could be used, introducing errors. With an enum only the applicable values can be used.

For example

public static final int SIZE_SMALL  = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE  = 3;

public void setSize(int newSize) { ... }

obj.setSize(15); // Compiles but likely to fail later

vs

public enum Size { SMALL, MEDIUM, LARGE };

public void setSize(Size s) { ... }

obj.setSize( ? ); // Can't even express the above example with an enum

enum Benefits:

  1. Enums are type-safe, static fields are not
  2. There is a finite number of values (it is not possible to pass non-existing enum value. If you have static class fields, you can make that mistake)
  3. Each enum can have multiple properties (fields/getters) assigned - encapsulation. Also some simple methods: YEAR.toSeconds() or similar. Compare: Colors.RED.getHex() with Colors.toHex(Colors.RED)

"such as the ability to easily assign an enum element a certain value"

enum EnumX{
  VAL_1(1),
  VAL_200(200);
  public final int certainValue;
  private X(int certainValue){this.certainValue = certainValue;}
}

"and consequently the ability to convert an integer to an enum without a decent amount of effort" Add a method converting int to enum which does that. Just add static HashMap<Integer, EnumX> containing the mapping java enum.

If you really want to convert ord=VAL_200.ordinal() back to val_200 just use: EnumX.values()[ord]


Nobody mentioned the ability to use them in switch statements; I'll throw that in as well.

This allows arbitrarily complex enums to be used in a clean way without using instanceof, potentially confusing if sequences, or non-string/int switching values. The canonical example is a state machine.


Main reason: Enums help you to write well-structured code where the semantic meaning of parameters is clear and strongly-typed at compile time - for all the reasons other answers have given.

Quid pro quo: in Java out of the box, an Enum's array of members is final. That's normally good as it helps value safety and testing, but in some situations it could be a drawback, for example if you are extending existing base code perhaps from a library. In contrast, if the same data is in a class with static fields you can easily add new instances of that class at runtime (you might also need to write code to add these to any Iterable you have for that class). But this behaviour of Enums can be changed: using reflection you can add new members at runtime or replace existing members, though this should probably only be done in specialised situations where there is no alternative: i.e. it's a hacky solution and may produce unexpected issues, see my answer on Can I add and remove elements of enumeration at runtime in Java.


I think an enum can't be final, because under the hood compiler generates subclasses for each enum entry.

More information From source


The first benefit of enums, as you have already noticed, is syntax simplicity. But the main point of enums is to provide a well-known set of constants which, by default, form a range and help to perform more comprehensive code analysis through type & value safety checks.

Those attributes of enums help both a programmer and a compiler. For example, let's say you see a function that accepts an integer. What that integer could mean? What kind of values can you pass in? You don't really know right away. But if you see a function that accepts enum, you know very well all possible values you can pass in.

For the compiler, enums help to determine a range of values and unless you assign special values to enum members, they are well ranges from 0 and up. This helps to automatically track down errors in the code through type safety checks and more. For example, compiler may warn you that you don't handle all possible enum values in your switch statement (i.e. when you don't have default case and handle only one out of N enum values). It also warns you when you convert an arbitrary integer into enum because enum's range of values is less than integer's and that in turn may trigger errors in the function that doesn't really accept an integer. Also, generating a jump table for the switch becomes easier when values are from 0 and up.

This is not only true for Java, but for other languages with a strict type-checking as well. C, C++, D, C# are good examples.


There are many good answers here, but none mentiones that there are highly optimized implementations of the Collection API classes/interfaces specifically for enums:

These enum specific classes only accept Enum instances (the EnumMap only accept Enums only as keys), and whenever possible, they revert to compact representation and bit manipulation in their implementation.

What does this mean?

If our Enum type has no more that 64 elements (most of real-life Enum examples will qualify for this), the implementations store the elements in a single long value, each Enum instance in question will be associated with a bit of this 64-bit long long. Adding an element to an EnumSet is simply just setting the proper bit to 1, removing it is just setting that bit to 0. Testing if an element is in the Set is just one bitmask test! Now you gotta love Enums for this!


example:

public class CurrencyDenom {
   public static final int PENNY = 1;
 public static final int NICKLE = 5;
 public static final int DIME = 10;
public static final int QUARTER = 25;}

Limitation of java Constants

1) No Type-Safety: First of all it’s not type-safe; you can assign any valid int value to int e.g. 99 though there is no coin to represent that value.

2) No Meaningful Printing: printing value of any of these constant will print its numeric value instead of meaningful name of coin e.g. when you print NICKLE it will print "5" instead of "NICKLE"

3) No namespace: to access the currencyDenom constant we need to prefix class name e.g. CurrencyDenom.PENNY instead of just using PENNY though this can also be achieved by using static import in JDK 1.5

Advantage of enum

1) Enums in Java are type-safe and has there own name-space. It means your enum will have a type for example "Currency" in below example and you can not assign any value other than specified in Enum Constants.

public enum Currency {PENNY, NICKLE, DIME, QUARTER};

Currency coin = Currency.PENNY; coin = 1; //compilation error

2) Enum in Java are reference type like class or interface and you can define constructor, methods and variables inside java Enum which makes it more powerful than Enum in C and C++ as shown in next example of Java Enum type.

3) You can specify values of enum constants at the creation time as shown in below example: public enum Currency {PENNY(1), NICKLE(5), DIME(10), QUARTER(25)}; But for this to work you need to define a member variable and a constructor because PENNY (1) is actually calling a constructor which accepts int value , see below example.

public enum Currency {
    PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
    private int value;

    private Currency(int value) {
            this.value = value;
    }
}; 

Reference: https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html


An enum is implictly final, with a private constructors, all its values are of the same type or a sub-type, you can obtain all its values using values(), gets its name() or ordinal() value or you can look up an enum by number or name.

You can also define subclasses (even though notionally final, something you can't do any other way)

enum Runner implements Runnable {
    HI {
       public void run() {
           System.out.println("Hello");
       }
    }, BYE {
       public void run() {
           System.out.println("Sayonara");
       }
       public String toString() {
           return "good-bye";
       }
    }
 }

 class MYRunner extends Runner // won't compile.

You get compile time checking of valid values when you use an enum. Look at this question.


There are many advantages of enums that are posted here, and I am creating such enums right now as asked in the question. But I have an enum with 5-6 fields.

enum Planet{
EARTH(1000000, 312312321,31232131, "some text", "", 12),
....
other planets
....

In these kinds of cases, when you have multiple fields in enums, it is much difficult to understand which value belongs to which field as you need to see constructor and eye-ball.

Class with static final constants and using Builder pattern to create such objects makes it more readable. But, you would lose all other advantages of using an enum, if you need them. One disadvantage of such classes is, you need to add the Planet objects manually to the list/set of Planets.

I still prefer enum over such class, as values() comes in handy and you never know if you need them to use in switch or EnumSet or EnumMap in future :)