Four be the things I am wiser to know: Idleness, sorrow, a friend, and a foe. Four be the things I'd been better without: Love, curiosity, freckles, and doubt. Three be the things I shall never attain: Envy, content, and sufficient champagne. Three be the things I shall have till I die: Laughter and hope and a sock in the eye. | ||
--Dorothy Parker, “Inventory” |
An enumeration type—sometimes known as an enumerated type, or more simply as an enum—is a type for which all values for the type are known when the type is defined. For example, an enum representing the suits in a deck of cards would have the possible values hearts, diamonds, clubs, and spades; and an enum for the days of the week would have the values Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday.
In some programming languages, enums are nothing more than a set of named integer values, but in the Java programming language an enum is a special kind of class, with an instance that represents each value of the enum.
An enum for the suits in a deck of cards can be declared as follows:
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }
In this basic form, an enum declaration consists of the keyword enum
, an identifier that names the enum, and a body that simply names each of the values, or constants, of the enum.[1] By convention, enum constants always have uppercase names. The enum constants are static fields of the class:
Suit currentSuit = ... ; if (currentSuit == Suit.DIAMONDS) ... ;
Each enum constant actually refers to an instance of the enum class. You cannot construct an instance of an enum by using new
—it is as if the enum had no accessible constructors. You may only use those objects created for the enum constants.
While this simple usage appears little different from declaring a set of named integer constants, it has the significant difference of being completely type-safe: It is impossible to assign anything to a reference of type Suit
except one of the four defined Suit
enum constants or null
. As you will see, enums also provide much more sophisticated usage than can be achieved with named integer constants.
Exercise 6.1: Define simple enums for the days of the week and traffic light colors.
Exercise 6.2: Redo your solution to Exercise 2.17 to use an enum to represent the TURN_LEFT
and TURN_RIGHT
constants. What advantage is there to using the enum?
Exercise 6.3: Redefine the Verbose
interface from Section 4.2.1 on page 121 to use an enum for the verbosity level instead of integer constants.
An enum is a special kind of class, but an enum declaration has restrictions on its form and use that are different from those of a normal class. An enum declaration is like a class declaration with two exceptions: The keyword enum
is used instead of class
, and before declaring any class members (or initialization blocks) an enum must first declare all of its enum constants. If an enum does declare anything other than its enum constants, then the list of enum constants must be termi ated by a semicolon. For example, this variation of Suit
provides a method to tell you how many suits there are:
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES; public static int getSize() { return 4; } }
For convenience, you're allowed to have a comma after the last enum constant (but before the semicolon if present), whether or not any other class declarations follow. This is useful for declaring an enum constant per line:
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES, }
Being able to keep the extraneous comma allows you to reorder lines without having to remember to add the comma to the old last line or remove it from the new last line. (Array initialization lists have the same feature—see page 175.)
An enum cannot be declared to extend
another type because all enums implicitly extend java.lang.Enum
, which we discuss a little later. Nor can any other type extend an enum (not even another enum), because all enum types act as if they are implicitly final
. An enum can declare that it implements one or more interfaces—in fact all enums are implicitly Serializable
(see “Object Serialization” on page 549) and Comparable
.
The possible members of an enum include all the class members: fields, methods, and nested types, including nested enums—though it should be rare to require such sophistication: The main attraction of enums is their simplicity. The enum constants themselves are implicitly static fields with the same type as the enum.
Every enum type E
has two static methods that are automatically generated for it by the compiler:
public static
E
[]
values()
Returns an array containing each of the enum constants in the order in which they were declared.
public static
E
valueOf(String name)
Returns the enum constant with the given name. If the name does not match an enum constant name exactly then an IllegalArgumentException
is thrown.
Note that the length of the array returned by values
tells you how many enum constants there are in the enum, so the getSize
method we demonstrated is not needed in practice.
An enum type is not allowed to override the finalize
method from Object
. Enum instances may never be finalized (see “Finalization” on page 449).
An enum declaration can be preceded by certain modifiers:
annotations—. Annotations and annotation types are discussed in Chapter 15.
access modifiers—. Nested enum declarations can have any of the access modifiers, while a top-level enum, as for a top-level class, is either public
or in the absence of an access modifier, accessible only within its own package.
static—. All nested enums are implicitly static
because they contain static members. By convention, the static
modifier is always omitted.
strict floating point—. All floating-point arithmetic within an enum declared to be strictfp
is evaluated strictly. See Section 9.1.3 on page 203 for details.
When multiple modifiers are applied to the same interface declaration, we recommend using the order listed above.
An enum cannot be declared abstract
because you cannot extend it to provide missing method implementations—however, an enum can declare abstract
methods. You'll shortly see how this apparent contradiction is resolved.
An enum also cannot be explicitly declared final
, though it acts as if it were final. You'll shortly see why this is so, too.
The simplest enum constant declaration just gives a name for each enum constant, as you have seen. Such enum constants implicitly define a public, static, and final field with the given name and of the same type as the enum. These implicit fields are initialized by constructing an instance of the enum as described below. An enum constant declaration cannot have modifiers applied to it, except for annotations (see Chapter 15).
An enum constant declaration that consists of only a name causes an object of the enum type to be created with the (implicit or explicit) no-arg constructor. An enum can declare arbitrary constructors, just like any other class. You select which constructor should be used for a particular enum constant by supplying arguments that match the constructor parameter types:
enum Suit { CLUBS("CLUBS"), DIAMONDS("DIAMONDS"), HEARTS("HEARTS"), SPADES("SPADES"); String name; Suit(String name) { this.name = name; } public String toString() { return name; } }
Here each Suit
value has a name
field set by the constructor that takes a String
, and in each enum constant declaration we provide the desired name argument. This is such a common thing to want with enum constants, however, that this functionality has been built-in so you don't have to write the name strings yourself—invoking thename
method on an enum constant will return its name as a String
.
You can get a feel for how an enum is internally defined from the following pseudo-code, which shows a mock class definition for the above Suit
enum:
class Suit extends Enum<Suit> // pseudo-code only implements Comparable<Suit>, Serializable { 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"); String name; Suit(String name) { this.name = name; } public String toString() { return name; } // ... compiler generated methods ... }
There is a bit more to the detail, but the above gives you the general idea.
The constructor to invoke is determined according to the usual rules for matching argument types with constructor parameter types—see “Finding the Right Method” on page 224.
There are three restrictions on the definition of an enum constructor:
All enum constructors are private. While you can use the private
access modifier in the constructor declaration, by convention it is omitted. Private constructors ensure that an enum type cannot be instantiated directly.
The constructor cannot explicitly invoke a superclass constructor. The chaining to the super constructor is handled automatically by the compiler.
An enum constructor cannot use a non-constant static field of the enum.
This last restriction requires a little explanation. Because each enum constant is a static field of the enum type, the constructors are executed during static initialization of the enum class. The enum constant declarations must be the first declarations in the type, so the constructors for these values will always be the first code executed during static initialization. Any other static fields will be initialized afterward. So if a constructor were to refer to a static (non-constant) field of the enum, it would see the default uninitialized value. This would nearly always be an error, and so it is simply disallowed.
The work-around is quite straight-forward: Declare a static initialization block that does what the constructor would like to have done. This block can refer to any enum constant or can iterate through all of them because all will have been constructed before the block can execute.
Exercise 6.4: Expand your traffic light color enum from Exercise 6.1 on page 152 so that each enum constant has a suitable Color
object that can be retrieved with getColor
.
Many enums define simple, passive types whose sole purpose is to provide the named enum constants—an enum like Suit
is a good example. Occasionally, enum constants will have state associated with them that will be set by a constructor and accessed with a method on the enum. For example, consider an enum that defined the nine planets of our solar system, and that allowed the mass of each planet to be set and queried. In some circumstances, the enum may represent an entity with inherent behavior that varies between the different enum constants—this is known as constant-specific behavior.
Suppose you were writing a computer chess program[2] and you wanted to represent the different kinds of chess pieces, you might use a simple enum like this:
enum ChessPiece { PAWN, ROOK, BISHOP, KNIGHT, KING, QUEEN; }
The rules for manipulating the different chess pieces could be defined in a class ChessRules
, which might then have a method that returns the set of reachable positions for a given kind of piece, given its current position:
Set<Position> reachable(ChessPiece type, Position current) { if (type == ChessPiece.PAWN) return pawnReachable(current); else if (type == ChessPiece.ROOK) return rookReachable(current); // ... else if (type == ChessPiece.QUEEN) return queenReachable(current); else throw new Error("Unknown type"); }
The job of reachable
is to dispatch actual calculations to methods that know how to handle specific chess pieces, so it has to consider all the possible values of the chess piece type that was passed to it. Whenever you see a chain of if
–else
statements, as above, or equivalently a switch
statement (which you'll learn about in Chapter 10) that distinguishes different objects or types of object, ask yourself if there is a way to have the object decide what needs to be done—after all, each object knows what it is. In this case, why can't you ask the chess piece for its set of reachable positions? It turns out you can—by adding constant-specific behavior to the enum:
enum ChessPiece { PAWN { Set<Position> reachable(Position current) { return ChessRules.pawnReachable(current); } }, ROOK { Set<Position> reachable(Position current) { return ChessRules.rookReachable(current); } }, // ... QUEEN { Set<Position> reachable(Position current) { return ChessRules.queenReachable(current); } }; // declare the methods defined by this enum abstract Set<Position> reachable(Position current); }
This time each named enum constant is followed by a class body that defines the methods for that enum constant—in this case dispatching to the appropriate ChessRules
method as before. The advantage of dispatching in the enum constants themselves is that you can't forget to handle the case for a specific value. Looking at the original code for reachable
you can see that it would be easy to leave out one of the values, only realizing this at runtime when the error is thrown. Also note that even though we have covered all the possible values in reachable
, we still must have that final else
clause because the compiler won't check to see if we have covered all possible values and the method must either return a value or throw an exception. By using constant-specific methods we moved the checking for completeness to compile time, which is always a good thing, and we avoided writing code that should never get executed.
The classes that are defined for each enum constant are effectively anonymous inner classes that extend the enclosing enum type—which is why you can't actually declare an enum to be final
: Even though it can't be directly extended, it can be implicitly extended by these anonymous inner classes.
As with other anonymous inner classes, the enum constant class body can define arbitrary instance fields, and methods, but it can't declare static members or define constructors. Also note that because enum constants are implicitly static fields, these anonymous inner classes have no enclosing instance.
To be directly accessible, the methods defined for each enum constant must be declared as methods of the enum type itself—either explicitly, as above for reachable
, or implicitly by an interface the enum implements. An enum type is allowed to declare an abstract
method, only if there is an implementation of that method for each and every enum constant.
Exercise 6.5: Redo Exercise 6.4 making getColor
an abstract method and defining constant-specific methods for each enum constant to return the correct Color
object. Would you recommend using constant-specific methods to do this?
All enum types implicitly extend java.lang.Enum
,[3] but no class is allowed to extend Enum
directly. Although Enum
does provide some methods that can be useful for working with enums, its main role is to establish some useful properties for all enum types:
The clone
method is overridden to be declared final
and to throw CloneNotSupportedException
—making it impossible to ever clone an enum instance.
The hashCode
and equals
methods are overridden and declared final
—ensuring consistent and efficient hashing for enums, and ensuring that equivalence is the same as identity.
The compareTo
method of interface java.lang.Comparable
is implemented and defined such that enum constants have a natural ordering based on their order of declaration—the first declared enum constant has the lowest position in the ordering.
Enum also provides a toString
implementation that returns the name of the enum constant, as we have mentioned, but which you can chose to override. It also provides a finalname
method that also returns the name of the enum constant as a String
. The difference between these two methods is that name
will return the exact name of the enum constant, while toString
may be overridden to return a more “user friendly” version of the name—for example, returning "Diamonds"
instead of "DIAMONDS"
.
The additional methods of Enum
are:
public final int
ordinal()
Returns the ordinal value of an enum constant. Enum constants are given ordinal values based on the order they are declared: the first declared constant has an ordinal value of zero, the second has an ordinal value of one, etc.
public final Class<
E
>
getDeclaringClass()
Returns the Class
object representing the enum type of this enum constant. This will be different from the value returned by Object.getClass
for any enum constant that is set to an anonymous inner class object.
The Enum
class also provides a static utility method, valueOf
, that takes a class object for an enum type, and a name, and returns the named enum constant from the given enum. If the enum doesn't have a enum constant by that name then IllegalArgumentException
is thrown.
In addition to the Enum
class, there are two highly efficient enum-specific collection classes: EnumSet
defines a set for use with enum values, and EnumMap
is a specialized map for which keys are enum values. These specialized collection classes are described further in Chapter 21.
The more sophisticated the type you are considering defining as an enum, the more thought you must give to whether enum is the right way to express that type. For simple uses like card suits, days of the week, and even the simple chess piece enum, all that is necessary is that you have a closed set of well-known instances—the decision to define an enum takes almost no thought.
When an enum declares enum constants with constant-specific behavior, additional considerations need to be made. The more sophisticated the behavior of a type, the more likely an application might need to specialize that behavior. Specialization of behavior is done through subclassing, and you cannot subclass an enum. Even something as innocuous as defining a logging, or profiling version of a given enum type is precluded. The same considerations that go into declaring a class final
apply to choosing whether to declare a sophisticated enum.
There is little an enum can do that you couldn't do by declaring distinct classes. But the packaging that enum provides is far more convenient to use, though with some restrictions, as you've seen. Additionally, enums are a part of the language and are recognized by other parts of the language. For example, enum constants can be used directly with a switch
statement (see page 232) whereas normal object references can not. Unless you need specialization through subclassing, it will almost always be better to use an enum type than to define your own classes.
CENSUS TAKER TO HOUSEWIFE: Did you ever have the measles, and, if so, how many?
[1] The term enum constant refers to those values, like CLUBS
and DIAMONDS
, declared in the enum type. Enum types can also have normal constants, just like other classes, that are static final fields of various types. We always use “enum constant” to refer to the former, and plain “constant” to refer to the latter.
[2] This example is based on an example given by Tim Peierls.
[3] Enum
is actually a generic class defined as Enum<T extends Enum<T>>.
This circular definition is probably the most confounding generic type definition you are likely to encounter. We're assured by the type theorists that this is quite valid and significant, and that we should simply not think about it too much, for which we are grateful.