3.6 Sets of Enums
Another common usage of constants
is to represent a feature set of a particular
item, such as a car, or even something really exciting, like a guitar.
You could then use bitwise operators to compare or check for specific
features. As in the lab on Maps of Enums, the Java language folks realized
this, and added another collection class for the purpose, java.util.EnumSet.
3.6.1 How do I do that?
First, examine the way this scenario might be handled in pre-Tiger days.
Example 3-5 is a simple class that defines some common guitar features.
Example 3-5. Guitar feature set
These are all features, and are all represented by powers of two. That
package com.oreilly.tiger.ch03;
public class OldGuitarFeatures {
public static final int ROSEWOOD = 0x01; // back/sides
public static final int MAHOGANY = 0x02; // back/sides
public static final int ZIRICOTE = 0x04; // back/sides
public static final int SPRUCE = 0x10; // top
public static final int CEDAR = 0x12; // top
public static final int AB_ROSETTE = 0x30; // abalone rosette
public static final int AB_TOP_BORDER = 0x32; // abalone top border
public static final int IL_DIAMONDS = 0x40; // diamond/square inlay
public static final int IL_DOTS = 0x42; // dots inlays
}
allows them to be combined like this:
With this initial work done (you could represent every guitar in a line this
int bourgeoisD150 = OldGuitarFeatures.ROSEWOOD |
OldGuitarFeatures.SPRUCE |
OldGuitarFeatures.AB_ROSETTE |
OldGuitarFeatures.IL_DIAMONDS;
way), you can test a specific guitar for a specific features, using the bitwise
AND operator:
Looking at the constants in OldGuitarFeatures, you should see that they
boolean hasAbRosette = (bourgeoisD150 & OldGuitarFeatures.IL_DIAMONDS) != 0;
are just another case of an enumerated type, and could be represented in
Tiger as shown in Example 3-6.
Example 3-6. Representing guitar features in Tiger
NOTEBe sure and
package com.oreilly.tiger.ch03;
public enum GuitarFeatures {
ROSEWOOD, // back/sides
MAHOGANY, // back/sides
ZIRICOTE, // back/sides
SPRUCE, // top
CEDAR, // top
AB_ROSETTE, // abalone rosette
AB_TOP_BORDER, // abalone top border
IL_DIAMONDS, // diamond/square inlay
IL_DOTS // dots inlays
}
continue to
compile with the
"-source 1.5" switch.
Using the
provided Ant
scripts takes care
of this, by the
way.However, operating on these constants with bitwise operators isn't possible,
at least without the help of a new class, java.util.EnumSet. Here
are the methods of this class you should be concerned with, most of
which are factories:
You may have to look at this for a minute to get the sense of thingsthe
// Returns a new EnumSet with all elements from the supplied type
public static EnumSet allOf(Class elementType);
// Returns a new EnumSet of the same type as the supplied set, but
// with all the values not in the supplied set; a mirror image
public static EnumSet complementOf(EnumSet e);
// Returns a new EnumSet from the provided collection
public static EnumSet copyOf(Collection c);
// Returns a new EnumSet with no values in it
public static EnumSet noneOf(Class elementType);
// Various methods to create an EnumSet with the supplied elements in it
public static EnumSet of(E e[, E e2, E e3, E e4, E e5]);
//Varags version
public static EnumSet of(E... e);
// Creates an EnumSet with a range of values
public static EnumSet range(E from, E to);
// returns a copy of the current set - not a factory method
public EnumSet clone( );
format is rather odd. But, to create a new EnumSet of all guitar features,
just use the following:
Simple enough, right? If you want only the back and side woods, you
EnumSet allFeatures = EnumSet.allOf(GuitarFeatures);
could use this notation:
You could also use the range( ) operator:
EnumSet backSides = EnumSet.of(GuitarFeatures.ROSEWOOD,
GuitarFeatures.MAHOGANY,
GuitarFeatures.ZIRICOTE);
EnumSet backSides = EnumSet.range(GuitarFeatures.ROSEWOOD,
GuitarFeatures.ZIRICOTE);
|
With your setup done, you can just use the contains( ) method, available
EnumSet noAbalone = EnumSet.complementOf(
EnumSet.of(GuitarFeatures.AB_ROSETTE, GuitarFeatures.AB_TOP_BORDER));
to all collection classes, to check for a value or values:
NOTEYou can't use
EnumSet bourgeoisD150 = EnumSet.of(GuitarFeatures.ROSEWOOD,
GuitarFeatures.SPRUCE,
GuitarFeatures.AB_ROSETTE,
GuitarFeatures.IL_DIAMONDS);
boolean hasAbRosette = bourgeoisD150.contains(GuitarFeatures.AB_ROSETTE);
varargs to work
with the of( )
method, due to
the usage of
generic types in
the factory
method.
Variable
arguments are
detailed in
Chapter 5.