Maximum Zeal ~ Emphatic prose on indulged fascinations

Effective Java Item 32: Use EnumSet instead of bit fields

A small tidbit of information which I came across in Effective Java Item 32 that I thought was worth a mention due to the fact that it is a little new in Java and less commonly found in use.

The Old Way – Int enum pattern

In the olden days one might have implemented enumeration sets using integers representing binary patterns and bitwise operations on those patterns. This was relatively easy and very efficient but it required reinventing the wheel and boilerplate code to some degree with every use case. It was also not type safe. An example follows.

Bitwise operations

In this particular case I couldn’t help but abstract the bitwise operations out of the main class requiring them but the normal pattern of use is that the bit operations are coupled with the class containing the integer constants.

package resolver;

public class IntEnumPatternResolver {

    private int current = 0;

    public boolean isEnabled(final int flag) {
        return (current & flag) == flag;
    }

    public int current() {
        return current;
    }

    public void enable(final int flag) {
        current |= flag;
    }

    public void disable(final int flag) {
        current &= ~flag;
    }

    public void toggle(final int flag) {
        current ^= flag;
    }

    /*
     * bulk operations
     */

    public void enableAll(final int... flags) {
        for (final int flag : flags) {
            enable(flag);
        }
    }


}
Integer based constants
package resolver;

public class IntEnumPatternExample {

    public static final int STYLE_BOLD          = 1 << 0; // 1
    public static final int STYLE_ITALIC        = 1 << 1; // 2
    public static final int STYLE_UNDERLINE     = 1 << 2; // 4
    public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8

    public static void main(String[] args) {
        final IntEnumPatternResolver resolver = new IntEnumPatternResolver();
        resolver.enableAll(STYLE_BOLD, STYLE_ITALIC, STYLE_STRIKETHROUGH, STYLE_UNDERLINE);
        resolver.disable(STYLE_STRIKETHROUGH);
        resolver.toggle(STYLE_UNDERLINE);
        print(resolver);
    }

    private static void print(IntEnumPatternResolver resolver) {
        assert resolver.isEnabled(STYLE_BOLD) == true;
        assert resolver.isEnabled(STYLE_ITALIC) == true;
        assert resolver.isEnabled(STYLE_UNDERLINE) == false;
        assert resolver.isEnabled(STYLE_STRIKETHROUGH) == false;

        System.out.println("STYLE_BOLD: " + resolver.isEnabled(STYLE_BOLD));
        System.out.println("STYLE_ITALIC: " + resolver.isEnabled(STYLE_ITALIC));
        System.out.println("STYLE_UNDERLINE: " + resolver.isEnabled(STYLE_UNDERLINE));
        System.out.println("STYLE_STRIKETHROUGH: " + resolver.isEnabled(STYLE_STRIKETHROUGH));
    }

}

The New Way – EnumSet<E>

package resolver;

import java.util.EnumSet;

public class EnumPatternExample {

    public enum Style {
        BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
    }

    public static void main(String[] args) {
        final EnumSet<Style> styles = EnumSet.noneOf(Style.class);
        styles.addAll(EnumSet.range(Style.BOLD, Style.STRIKETHROUGH)); // enable all constants
        styles.removeAll(EnumSet.of(Style.UNDERLINE, Style.STRIKETHROUGH)); // disable a couple
        assert EnumSet.of(Style.BOLD, Style.ITALIC).equals(styles); // check set contents are correct
        System.out.println(styles);
    }

}

Discussion

As you can see the new way has far less boilerplate code and the complex and error prone bitwise logic is nicely encapsulated in the EnumSet type as opposed to being in IntEnumPatternResolver (above). As the API docs say EnumSets are represented internally as bit vectors and are extremely compact and efficient and bulk operations are also very quick as long as you pass an EnumSet where the expect argument type is Set.

Update [02/07/2011]: Nice to see this featured on StackOverflow as the top voted answer to that question.

4 Responses to Effective Java Item 32: Use EnumSet instead of bit fields

  1. [...] looks like it's idiomatic in Java to use an enum to represent the different options and use an EnumSet to toggle them and check them, which is presumably using the enum as a bit field [...]

  2. Patrick Pentz says:

    An important problem that the enums solve is the binding of the bit-pattern names (enums) to the masks (EnumSet). With the previous solutions, you cannot be certain that some named constant really belonged to the mask, especially in large systems. I work with an old, very large, SCADA/EMS system, written in Fortran, with easily thousands of masks stored in databases with named constants applied against them. Who knows if the correct names are being used?

  3. Angel says:

    http://weblogs.java.net/blog/mkarg/archive/2010/01/03/fun-enumset

    a caveat about EnumSet

    by mcnepp – 2010-01-05 02:15
    Hi Mark, The JavaDoc for EnumSet advertizes it as a superior alternative to bitmasks.
    Rather unfortunately, EnumSet is modifiable!
    Therefore, declaring final static instances of EnumSet as a direct substitute for bitmasks cannot be recommended (as they could be modified by external code).
    Instead, one needs to wrap the EnumSet in a “normal” java.util.Set like this:
    public static final Set WORKDAYS = Collections.unmodifiableSet(EnumSet.range(MONDAY, FRIDAY));

  4. Bob says:

    OK, but Collections.unmodifiableSet (…) shouldn’t be too hard on the eyes, and what is a “normal” set anyway? (Set is just an interface – or contract as to what methods must be supported by the implementation). Collections.unmodifiableSet is just a thin wrapper that intercepts mutator methods and throws an UnsupportedOperationException should someone try to use them. There’s no harm to using it – the efficient underlying bitwise storage of an EnumSet would not be impacted – EnumSet is still the implementation of the interface!