Comparison and Bounds
3.5 Enumerated Types
public static <E>
Comparator<List<E>> listComparator(final Comparator<? super E> comp) { return new Comparator<List<E>>() {
public int compare(List<E> list1, List<E> list2) { int n1 = list1.size();
int n2 = list2.size();
for (int i = 0; i < Math.min(n1,n2); i++) { int k = comp.compare(list1.get(i), list2.get(i));
if (k != 0) return k;
}
return (n1 < n2) ? -1 : (n1 == n2) ? 0 : 1;
} };
}
The loop compares corresponding elements of the two lists, and terminates when cor- responding elements are found that are not equal (in which case, the list with the smaller element is considered smaller) or when the end of either list is reached (in which case, the shorter list is considered smaller). This is the usual ordering for lists; if we convert a string to a list of characters, it gives the usual ordering on strings.
And here is the first line of the declaration for the Season class:
class Season extends Enum<Season>
Example 3-3. Comparators class Comparators { public static <T>
T max(Collection<? extends T> coll, Comparator<? super T> cmp) {
T candidate = coll.iterator().next();
for (T elt : coll) {
if (cmp.compare(candidate, elt) < 0) { candidate = elt; } }
return candidate;
}
public static <T extends Comparable<? super T>>
T max(Collection<? extends T> coll) {
return max(coll, Comparators.<T>naturalOrder());
}
public static <T>
T min(Collection<? extends T> coll, Comparator<? super T> cmp) {
return max(coll, reverseOrder(cmp));
}
public static <T extends Comparable<? super T>>
T min(Collection<? extends T> coll) {
return max(coll, Comparators.<T>reverseOrder());
}
public static <T extends Comparable<? super T>>
Comparator<T> naturalOrder() {
return new Comparator<T>() {
public int compare(T o1, T o2) { return o1.compareTo(o2); } };
}
public static <T> Comparator<T>
reverseOrder(final Comparator<T> cmp) {
return new Comparator<T>() {
public int compare(T o1, T o2) { return cmp.compare(o2,o1); } };
}
public static <T extends Comparable<? super T>>
Comparator<T> reverseOrder() {
return new Comparator<T>() {
public int compare(T o1, T o2) { return o2.compareTo(o1); } };
} }
3.5 Enumerated Types | 43
Example 3-4. Base class for enumerated types
public abstract class Enum<E extends Enum<E>> implements Comparable<E> { private final String name;
private final int ordinal;
protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal;
}
public final String name() { return name; } public final int ordinal() { return ordinal; } public String toString() { return name; } public final int compareTo(E o) { return ordinal - o.ordinal;
} }
Example 3-5. Class corresponding to an enumerated type // corresponds to
// enum Season { WINTER, SPRING, SUMMER, FALL } final class Season extends Enum<Season> {
private Season(String name, int ordinal) { super(name,ordinal); } public static final Season WINTER = new Season("WINTER",0);
public static final Season SPRING = new Season("SPRING",1);
public static final Season SUMMER = new Season("SUMMER",2);
public static final Season FALL = new Season("FALL",3);
private static final Season[] VALUES = { WINTER, SPRING, SUMMER, FALL };
public static Season[] values() { return VALUES.clone(); } public static Season valueOf(String name) {
for (Season e : VALUES) if (e.name().equals(name)) return e;
throw new IllegalArgumentException();
} }
Matching things up, we can begin to see how this works. The type variable E stands for the subclass of Enum that implements a particular enumerated type, such as Season. Every E must satisfy:
E extends Enum<E>
So we can take E to be Season, since:
Season extends Enum<Season>
Furthermore, the declaration of Enum tells us that:
Enum<E> implements Comparable<E>
So it follows that:
Enum<Season> implements Comparable<Season>
Hence, we are allowed to compare two values of type Season with each other, but we cannot compare a value of type Season with a value of any other type.
Without the type variable, the declaration of the Enum class would begin like this:
And the declaration for the Season class would begin like this:
class Season extends Enum
This is simpler, but it is too simple. With this definition, Season would implement Comparable<Enum> rather than Comparable<Season>, which would mean that we could compare a value of type Season with a value of any enumerated type, which is certainly not what we want!
In general, patterns like T extends Comparable<T> and E extends Enum<E> often arise when you want to pin down types precisely. We’ll see further examples of this when we look at the Strategy and Subject-Observer design patterns, in Sections Section 9.4 and Section 9.5.
The rest of the definition is a straightforward application of the typesafe enum pattern described by Joshua Bloch in Effective Java (Addison-Wesley), which in turn is an in- stance of the singleton pattern described by Gamma, Helm, Johnson, and Vlissides in Design Patterns (Addison-Wesley).
The base class Enum defines two fields, a string name and an integer ordinal, that are possessed by every instance of an enumerated type; the fields are final because once they are initialized, their value never changes. The constructor for the class is protected, to ensure that it is used only within subclasses of this class. Each enumeration class makes the constructor private, to ensure that it is used only to create the enumerated constants. For instance, the Season class has a private constructor that is invoked exactly four times in order to initialize the final variables WINTER, SPRING, SUMMER, and FALL. The base class defines accessor methods for the name and ordinal fields. The toString method returns the name, and the compareTo method just returns the difference of the ordinals for the two enumerated values. (Unlike the definition of Integer in Sec- tion 3.1, this is safe because there is no possibility of overflow.) Hence, constants have the same ordering as their ordinals—for example, WINTER precedes SUMMER.
Lastly, there are two static methods in every class that corresponds to an enumerated type. The values method returns an array of all the constants of the type. It returns a (shallow) clone of the internal array. Cloning is vital to ensure that the client cannot alter the internal array. Note that you don’t need a cast when calling the clone method, because cloning for arrays now takes advantage of covariant return types (see Section 3.8). The valueOf method takes a string and returns the corresponding constant, found by searching the internal array. It returns an IllegalArgumentException if the string does not name a value of the enumeration.