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".