SCJP Study Guide:
Declarations, Initialization and Scoping


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents
Enums

Enums


In prior releases, Java does not support the concept of user-defined enumerated types.

What is an enumerated type? An enumerated type is a type whose legal values consist of a fixed set of constants.

The standard way to represent an enumerated type was the int Enum pattern, for example, to define the four seasons in a year:

public class SEASON {
	public static final int WINTER = 0;
	public static final int SPRING = 1;
	public static final int SUMMER = 2;
	public static final int FALL   = 3;
}

This pattern has many problems, such as, not typesafe, no namespace, printed values are uninformative, and not convenient, etc.

In 5.0, Java adds support for enumerated types. The new enum has a lot of advantages including:

  1. It provides strong compile-time type safety
  2. It provides a separate namespace for each enum type and thus eliminates the need to include a prefix in each constant name
  3. Constants are not compiled into clients so you can freely add, remove, or reorder them without recompiling the clients
  4. Printed values are informative instead of just numbers
  5. Enum constants can be used wherever objects can be used

Besides the above, the new enum type defines a full-fledged class. It allows you to add arbitrary methods and fields to an enum type, to implement arbitrary interfaces, and more.

Enum types provide high-quality implementations of all the Object methods. They are Comparable and Serializable, and the serial form is designed to withstand arbitrary changes in the enum type.

This flexible object-oriented enumerated type facility allows you to create enumerated types with arbitrary methods and fields. It provides all the benefits of the Typesafe Enum pattern without the verbosity and the error-proneness.

Enum Declaration


The declaration of the a Java enum type is very similar to other programming languages. You define an enumerated type by using the enum keyword. Here is a general Syntax for decaring a top level enums:

public enum enumIdentifier {
  .... //enumBody
} 

For example, To define the four seasons of a year, it's

enum Season { WINTER, SPRING, SUMMER, FALL }

Note: the word enum is reserved, you can't use it as class or variable identifier any more.

Only "public" modifier and "none (package)"  modifier can be used by the declaration of top-level enum.

There are a couple of important things to note about enum declarations. As an example, consider the following declaration:

public enum MainMenu {FILE, EDIT, FORMAT, VIEW};

The above enum declaration generates a class (MainMenu in the above example), which automatically implements the Comparable<MainMenu> and Serializable interfaces, and provides several members including:

  • Static variables FILE, EDIT, FORMAT, and VIEW
  • Static method values(), which is an array containing the constants in the enum
  • static method valueOf(String) that returns the appropriate enum for the string passed in
  • Appropriately overloaded equals(), hasCode, toString(), and compareTo() methods.

Here is a complete example that declares an enumeration and then prints the values:

public class Example {
  public enum MainMenu {FILE, EDIT, FORMAT, VIEW}

  public static void main(String[] argv) {
    for (MainMenu menu : MainMenu.values()) 
      System.out.println(menu);    
  }
}

And the following segment of code shows another example using the switch statement:

for(MainMenu menu : MainMenu.values()) {
  switch(menu) {
    case FILE:
      System.out.println("FILE Menu");
      break;
    case EDIT:
      System.out.println("EDIT Menu");
      break;
    case FORMAT:
      System.out.println("FORMAT Menu");
      break;
    case VIEW:
      System.out.println("VIEW Menu");
      break;
  }
}

The use of class modifiers in enum declarations is as for class declarations, with a few additional restrictions. All enum declarations are implicitly final unless they contain constant-specific class bodies (which result in implicit subclasses). It is permissible to use the final modifier on an enum declaration without constant-specific class bodies, but it has no effect (and is discouraged).

Enum declarations may not use the class modifier abstract unless they contain constant-specific class bodies for every enum constant, and any abstract methods declared in the (optional) class body declarations are overridden in all the constant-specific class bodies. Enum member classes are implicitly static. Regardless of what class modifiers are used, it is illegal to explicitly instantiate an enum (using new).

Eums can be declared as the top-level class or as an inner class.


Enum constructors

Each constant declaration can be followed by an argument list that is passed to the constructor of the enum type having the matching parameter signature.

An implicit standard constructor is created if no constructors are provided for the enum type.

As an enum cannot be instantiated using the new operator, the constructors cannot be called explicitly.

Example of enum constructors:

public enum Meal {

 BREAKFAST(7, 30), LUNCH(12, 15), DINNER(19, 45);

 private int hh;
 private int mm;

 Meal(int hh, int mm) {
	assert (hh >= 0 && hh <= 23) : "Illegal hour.";
	assert (mm >= 0 && mm <= 59) : "Illegal mins.";
	this.hh = hh;
	this.mm = mm;
 }

 public int getHour() {
	return hh;
 }

 public int getMins() {
	return mm;
 }

Methods provided for the enum types


Names of members declared in an enum type cannot conflict with automatically generated member names:

  • The enum constant names cannot be redeclared.
  • The following methods cannot be redeclared:
  • // Returns an array containing the constants of this enum class, 
    // in the order they are declared. 
    static < this enum class >[] values() 
    
    // Return the enum constant with the specified name 
    static < this enum class > valueOf(String name) 
     
  • Enum types are based on the java.lang.Enum class which provides the default behavior.
  • Enums cannot declare methods which override the final methods of the java.lang.Enum class:
  • clone(), compareTo(Object), equals(Object), getDeclaringClass(), hashCode(), name(), ordinal(). The final methods do what their names imply, but the clone() method throws an CloneNotSupportedException, as an enum constant cannot be cloned.

Note that the enum constants must be declared before any other declarations in an enum type.

public enum Meal { 

 int q = 1; // WRONG ! Compilation error ! 

 BREAKFAST(7, 30), LUNCH(12, 15), DINNER(19, 45); 

 private int hh; 
 

Example of using enum type:

public class MealClient { 
 public static void main(String[] args) { 
  for (Meal meal : Meal.values()) 
   System.out.println(meal + " served at " + meal.getHour() + ":" 
   + meal.getMins() + ", has the ordinal value " 
   + meal.ordinal()); 
  } 
} 

The output will be:

BREAKFAST served at 7:30, has the ordinal value 0 
LUNCH served at 12:15, has the ordinal value 1 
DINNER served at 19:45, has the ordinal value 2 

Extending enum types: constant-specific class bodies

Constant-specific class bodies define anonymous classes inside an enum type that extend the enclosing enum type.

Instance methods declared in these class bodies are accessible outside the enclosing enum type only if they override accessible methods in the enclosing enum type.

An enum type that contains constant-specific class bodies cannot be declared final:

public enum Meal { 
 // Each enum constant defines a constant-specific 
 //class body 
 BREAKFAST(7, 30) { 
  public double mealPrice() { 
   double breakfastPrice = 10.50; 
   return breakfastPrice; 
  } 
 }, 
...... 
 // WRONG! Compilation error! Cannot override the final method 
 //from Meal final double mealPrice() { return 0; }  

Correct example:

public enum Meal { 
 // Each enum constant defines a constant-specific class body 
 BREAKFAST(7, 30) { 
  public double mealPrice() { 
   double breakfastPrice = 10.50; 
   return breakfastPrice; 
  } 
 }, 
...... 

 // Abstract method which the constant-specific class body 
 abstract double mealPrice(); 
......  


Enum Collections


Two classes have been added to java.util in support of enums: EnumSet (a high-performance Set implementation for enums; all members of an enum set must be of the same enum type) and EnumMap (a high-performance Map implementation for use with enum keys).

java.util.EnumSet

public abstract class EnumSet<E extends Enum<E>>
extends AbstractSet<E>
implements Cloneable, Serializable

This class is a member of the Java Collections Framework.

A specialized Set implementation for use with enum types. All of the elements in an enum set must come from a single enum type that is specified, explicitly or implicitly, when the set is created. Enum sets are represented internally as bit vectors. This representation is extremely compact and efficient.

Like most collection implementations EnumSet is not synchronized. If multiple threads access an enum set concurrently, and at least one of the threads modifies the set, it should be synchronized externally.

Null elements are not permitted.

The EnumSet class provides three benefits a normal set does not:

  1. Various creation methods that simplify the construction of a set based on an Enumeration
  2. Guaranteed ordering of the elements in the set based on their order in the enumeration constants are declared
  3. Performance and memory benefits not nearly possible with a regular set implementation

Method summary for the abstract class EnumSet:

// Creates an enum set containing all of the 
// elements in the specified element type. 
allOf(Class< E > elementType) 

// Returns a copy of this set. 
clone() 

// Creates an enum set with the same element 
// type as the specified enum set, initially 
// containing all the elements of this type 
// that are not contained in the specified set. 
complementOf(EnumSet< E > s) 

// Creates an enum set initialized from 
// the specified collection. 
copyOf(Collection< E > c) 

// Creates an enum set with the same element 
// type as the specified enum set, initially 
// containing the same elements (if any). 
copyOf(EnumSet< E > s) 

// Creates an empty enum set with the 
// specified element type. 
noneOf(Class< E > elementType) 

// These factory methods creates an enum set 
// initially containing the specified 
// element(s). Note that enums cannot be used 
// in varargs as it is not legal to use varargs 
// with parameterized types. 
of(E e) 
of(E e1, E e2) 
of(E e1, E e2, E e3) 
of(E e1, E e2, E e3, E e4) 
of(E e1, E e2, E e3, E e4, E e5) 

// Creates an enum set initially containing all of the 
// elements in the range defined by 
// the two specified endpoints. 
range(E from, E to) 

The following is an example of using the EnumSet:

public class CreateTShirt {
 
    private enum TShirtSize { SMALL, MEDIUM, LARGE };
    
    public static void main(String[] args) {
     Set<TShirtSize> s = EnumSet.of(TShirtSize.SAMLL, 
		TShirtSize.MEDIUM, TShirtSize.LARGE);
     createTShirt(s);
    }
    
    public static void createTShirt(Set<TShirtSize> allSizes) {
	for(TShirtSize aSize : allSizes) {
	  switch(aSize) :{
		case SMALL:
		  System.out.println("A small T-shirt");
		  break;
		case MEDIUM:
		  System.out.println("A medium T-shirt");
		  break;
		case LARGE:
		  System.out.println("A large T-shirt");
		  break;
	  }
	}
    }
}

java.util.EnumMap


public class EnumMap<K extends Enum<K>,V>
extends AbstractMap<K,V>
implements Serializable, Cloneable

This class is a member of the Java Collections Framework.

A specialized Map implementation for use with enum type keys.

All of the keys in an enum map must come from a single enum type that is specified, explicitly or implicitly, when the map is created.

Enum maps are represented internally as arrays. This representation is extremely compact and efficient.

Null keys are not permitted.

Like most collection implementations EnumMap is not synchronized. If multiple threads access an enum map concurrently, and at least one of the threads modifies the map, it should be synchronized externally.

Constructor summary of the class EnumMap:

// Creates an empty enum map with the 
// specified key type. 
EnumMap(Class< K > keyType) 

// Creates an enum map with the same key 
// type as the specified enum map, initially 
// containing the same mappings (if any). 
EnumMap(EnumMap< K,? extends V > m) 

// Creates an enum map initialized from the 
// specified map. 
EnumMap(Map< K,? extends V > m)

Method summary of the class EnumMap:

// Removes all mappings from this map. 
void clear() 

// Returns a shallow copy of this enum map. 
EnumMap< K,V > clone() 

// Returns true if this map contains a 
// mapping for the specified key. 
boolean containsKey(Object key) 

// Returns true if this map maps one or 
// more keys to the specified value. 
boolean containsValue(Object value) 

// Returns a Set view of the mappings 
// contained in this map. 
Set< Map.Entry< K,V > > entrySet() 

// Compares the specified object with 
// this map for equality. 
boolean equals(Object o) 

// Returns the value to which this map maps 
// the specified key, or null if this map contains 
// no mapping for the specified key. 
V get(Object key) 

// Returns a Set view of the keys 
// contained in this map. 
Set< K > keySet() 

// Associates the specified value with the 
// specified key in this map. 
V put(K key, V value) 

// Copies all of the mappings from the 
// specified map to this map. 
void putAll(Map< ? extends K,? extends V > m) 

// Removes the mapping for this key from 
// this map if present. 
V remove(Object key) 

// Returns the number of key-value mappings 
// in this map. 
int size() 

// Returns a Collection view of the values 
// contained in this map. 
Collection< V > values()

The following is an example of using the EnumMap:

import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class CreateTShirt {
 
    private enum TShirtSize { SMALL, MEDIUM, LARGE };

	public static void main(String[] args) {

		int[] peopleBySize = { 35, 40, 60 };

		// Create a HashMap of people by T shirt size
		Map<TShirtSize, Integer> ordinaryMap = 
				new HashMap<TShirtSize, Integer>();
		for (TShirtSize tShirtSize : TShirtSize.values()) {
			ordinaryMap.put(tShirtSize, 
					peopleBySize[tShirtSize.ordinal()]);
		}
		out.println("Ordinary Map: " + ordinaryMap);

		//Create an EnumMap from a HashMap
		EnumMap<TShirtSize, Integer> enumMap = 
				new EnumMap<TShirtSize, Integer>(
				ordinaryMap);

		// update entry
		enumMap.put(TShirtSize.SMALL, 33);
		enumMap.put(TShirtSize.MEDIUM, 42);
		System.out.println("updated Map: " + enumMap);

		// print all the Values
		Collection<Integer> totalPeople = enumMap.values();
		System.out.println("total people: " + totalPeople);

		// print all the Keys
		Set<TShirtSize> sizes = enumMap.keySet();
		System.out.println("all the size: " + sizes);
	}
}

Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |