This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The int enum pattern - severely deficient! | |
public static final int APPLE_FUJI = 0; | |
public static final int APPLE_PIPPIN = 1; | |
public static final int APPLE_GRANNY_SMITH = 2; | |
public static final int ORANGE_NAVEL = 0; | |
public static final int ORANGE_TEMPLE = 1; | |
public static final int ORANGE_BLOOD = 2; |
Here is how it looks in its simplest enum form.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public enum Apple { FUJI, PIPPIN, GRANNY_SMITH } | |
public enum Orange { NAVEL, TEMPLE, BLOOD } |
The basic idea behind Java's enum types is simple: they are classes that export one instance for each enumeration constant via a public static final field. Enum types are effectively final, by virtue of having no accessible constructors. They are generalization of singleton.
Let's go on with richer enum forms with methods and fields. For a nice example of a rich enum type, consider the eight planets of our solar system. Each planet has a mass and radius, and from these two attributes youcan compute its surface gravitiy.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Enum type with data and behavior | |
public enum Planet { | |
MERCURY(3.302e+23, 2.439e6), | |
VENUS (4.869e+24, 6.052e6), | |
EARTH (5.975e+24, 6.378e6), | |
MARS (6.419e+23, 3.393e6), | |
JUPITER(1.899e+27, 7.149e7), | |
SATURN (5.685e+26, 6.027e7), | |
URANUS (8.683e+25, 2.556e7), | |
NEPTUNE(1.024e+26, 2.477e7); | |
private final double mass; // In kilograms | |
private final double radius; // In meters | |
private final double surfaceGravity; // In m / s^2 | |
// Universal gravitational constant in m^3 / kg s^2 | |
private static final double G = 6.67300E-11; | |
// Constructor | |
Planet(double mass, double radius) { | |
this.mass = mass; | |
this.radius = radius; | |
surfaceGravity = G * mass / (radius * radius); | |
} | |
public double mass() { return mass; } | |
public double radius() { return radius; } | |
public double surfaceGravity() { return surfaceGravity; } | |
public double surfaceWeight(double mass) { | |
return mass * surfaceGravity; // F = ma | |
} | |
} |
Enums are by their nature immutable, so all fields should be final.
While the Planet enum is simple, it is surprisingly powerful. Note that Planet, like all enums, has a static values method that returns an array o fits values in the order they were declared. Note also that the toString method returns the declared name of each enum value.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class WeightTable { | |
public static void main(String[] args) { | |
double earthWeight = Double.parseDouble(args[0]); | |
double mass = earthWeight / Planet.EARTH.surfaceGravity(); | |
for (Planet p : Planet.values()) | |
System.out.printf("Weight on %s is %f%n", | |
p, p.surfaceWeight(mass)); | |
} | |
} |
The technique demonstrated in the Planet example are sufficient for most enum types, but sometimes you need to associate fundamentally different behavior with each constant. One way to achieve this is to switch on the value of the enum.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Enum type that switches on its own value - questionable | |
public enum Operation { | |
PLUS, MINUS, TIMES, DIVIDE; | |
// Do the arithmetic op represented by this constant | |
double apply(double x, double y) { | |
switch(this) { | |
case PLUS: return x + y; | |
case MINUS: return x - y; | |
case TIMES: return x * y; | |
case DIVIDE: return x / y; | |
} | |
throw new AssertionError("Unknown op: " + this); | |
} | |
} |
This code works but it isn't very pretty. Consider below powerful side of Enum, implementing abstract method in each Enum instance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Enum type with constant-specific method implementations | |
public enum Operation { | |
PLUS { double apply(double x, double y){return x + y;} }, | |
MINUS { double apply(double x, double y){return x - y;} }, | |
TIMES { double apply(double x, double y){return x * y;} }, | |
DIVIDE { double apply(double x, double y){return x / y;} }; | |
abstract double apply(double x, double y); | |
} |
If you add a new constant to the second version of Operation, it is unlikely that you'll forget t oprovide an apply method, as the method immediately follows each constant decleration.
So when should you use enums? Anytime you need a fixed set of constants. Of course, this includes "natural enumerated types" such as planets, the days of the week, and the chess pieces, but it also includes other sets for which you know all the possible values at compile time such as choices on a menu, operation codes etc.
No comments:
Post a Comment