Define a class representing a single element of the enumerated type and provide no public constructor. An enumeration is a new type since Java 5 (jdk1.5). Before jdk1.4, you can create a similar type that is much better and type safe. This is so-called Typesafe Enum pattern.
//simple enum type public enum Coin { PENNY, NICKEL, DIME, QUARTER; } to use: switch(coin) { case PENNY: return 1; case NICKEL: return 5; case DIME: return 10; case QUARTER: return 25; default: return 0; } //enum type with a method public enum Coin { PENNY, NICKEL, DIME, QUARTER; int value(){ switch(this) { case PENNY: return 1; case NICKEL: return 5; case DIME: return 10; case QUARTER: return 25; default: return 0; } } } to use: int v = coin.value(); //enum type with abstract type public enum Coin { PENNY { int value(){ return 1;} }, NICKEL { int value(){ return 5;} }, DIME { int value() { return 10;} }, QUARTER { int value() {return 25;} }; abstract int value(); } //enum type with constructor public enum Coin { PENNY(1), NICKEL(5), DIME(10), QUARTER(25); private int coinValue; int value() {return coinValue;} Coin(int value){ coinValue = value; } } //enum combining with visitor design pattern public abstract class CoinVisitor { void visitPenny(Coin c){} void visitNickel(Coin c){} void visitDime(Coin c){} void visitQuarter(Coin c){} } public enum Coin { PENNY { void accept(CoinVisitor cv) {cv.visitPenny(this);} }, NICKEL { void accept(CoinVisitor cv) {cv.visitNickel(this);} }, DIME { void accept(CoinVisitor cv) {cv.visitDime(this);} }, QUARTER { void accept(CoinVisitor cv) {cv.visitQuarter(this);} }; abstract void accept(CoinVisitor cv); }
If you are a C or C++ or C# programmer, you may be familiar with the code below.
typedef enum { WHITE, BLACK, YELLOW }color_t; typedef enum { CAMRY, HONDA, FORD }car_t;
Once defined, an enumeration is used very much like an integer type. By default enumerator values are assigned increasing from 0, so WHITE == 0, BLACK == 1 and YELLOW == 2, and so does for enum car_t. You may see the following code:
color_t myColor = FORD;
The above code has a problem because the color and car have been mixed. Such type is not safe.
So let's see how Java does it. Use Java equivalent design, for example, define a playing card class, you may try to do it in the following way,
public class PlayingCard { public static final int SUIT_CLUBS =0; public static final int SUIT_DIAMONDS =1; public static final int SUIT_HEARTS =2; public static final int SUIT_SPADES =3; ... }
The above code seems OK for switch statement, but is problematic and not type safe either.
Here we use typesafe enum pattern, use a class to represent constants:
//The typesafe enum pattern public class Suit { private final String name; public static final Suit CLUBS =new Suit("clubs"); public static final Suit DIAMONDS =new Suit("diamonds"); public static final Suit HEARTS =new Suit("hearts"); public static final Suit SPADES =new Suit("spades"); private Suit(String name){ this.name =name; } public String toString(){ return name; } }
Note that, the constructor is private, it prevents subclasses. The constants are static so they are easily accessible. Such design makes a compile-time type safe.
You may use it somewhere like C's enum type in the following way:
private static final Suit[] CARD_SUIT = { CLUBS, DIAMONDS, HEARTS, SPADES }; ... if (suit ==Suit.CLUBS){ ... }else if (suit ==Suit.DIAMONDS){ ... }else if (suit ==Suit.HEARTS){ ... }else if (suit ==Suit.SPADES){ ... }else{ throw new NullPointerException("Null Suit"); //suit ==null }
Later, you want to expand Suit class, like the following, you don't need to recompile the client class.
//Ordinal-based typesafe enum public class Suit implements Comparable { private final String name; public static final Suit CLUBS =new Suit("clubs"); public static final Suit DIAMONDS =new Suit("diamonds"); public static final Suit HEARTS =new Suit("hearts"); public static final Suit SPADES =new Suit("spades"); //Ordinal of next suit to be created private static int nextOrdinal =0; //Assign an ordinal to this suit private final int ordinal =nextOrdinal++; private Suit(String name){ this.name =name; } public String toString(){ return name; } public int compareTo(Object o){ return ordinal -((Suit)o).ordinal; } }
Reference: book "Effective Java Programming".