pattern

Enum in Java with int conversion

If you’ve found this post, chances are you want to convert from an enum to an int, or alternatively from an int to an enum in Java. Well… you can’t. Java has the most robust implementation of the ‘enum pattern’ of any language, in essence enums are a class that can only be instantiated once. This makes them ideal as singletons by the way…

Anyway, since enums are a class, you need to provide the int functionality yourself. For my example, I’m going to be making a ‘difficulty’ enum which should be very familiar with anyone making games for Android. First declare your enum:

public enum Difficulty
{
    EASY(0),
    MEDIUM(1),
    HARD(2);

    /**
     * Value for this difficulty
     */
    public final int Value;

    private Difficulty(int value)
    {
        Value = value;
    }
}

This should be fairly familiar to you if you’ve worked with Java enums for any length of time. Each enum is effectively an instance of itself, so we can pass values to the constructor. We store the value in a final field (enums are by definition immutable – don’t go breaking this without good reason!) for future retrieval. Ideally the value should be accessed by a getter rather than directly, but I think in this case it makes more sense to making it a public field. The user can’t change it, and we don’t need any code to run on access; so I think a getter would just reduce performance and make consumption that little bit more tedious.

Now we need to add the important part, the conversion from int to the enum itself:

// Mapping difficulty to difficulty id
private static final Map<Integer, Difficulty> _map = new HashMap<Integer, Difficulty>();
static
{
    for (Difficulty difficulty : Difficulty.values())
        _map.put(difficulty.Value, difficulty);
}

/**
 * Get difficulty from value
 * @param value Value
 * @return Difficulty
 */
public static Difficulty from(int value)
{
    return _map.get(value);
}

So what are we doing here, exactly? Well we create a map that will be our lookup table, we do this rather than a switch statement to minimise long-term maintenance. If someone added an extra enumeration in the future, they may forget to update the switch statement – and this error won’t be picked up until runtime, and even then it may appear as incorrect behaviour rather than throwing an exception. After we’ve created the map, we populate it automatically by looping through all of the enums and adding them and their value to the map.

So there you have it, the proper pattern for adding int values to an enumeration. The code in full is below:

public enum Difficulty
{
    EASY(0),
    MEDIUM(1),
    HARD(2);

    /**
     * Value for this difficulty
     */
    public final int Value;

    private Difficulty(int value)
    {
        Value = value;
    }

    // Mapping difficulty to difficulty id
    private static final Map<Integer, Difficulty> _map = new HashMap<Integer, Difficulty>();
    static
    {
        for (Difficulty difficulty : Difficulty.values())
            _map.put(difficulty.Value, difficulty);
    }

    /**
     * Get difficulty from value
     * @param value Value
     * @return Difficulty
     */
    public static Difficulty from(int value)
    {
        return _map.get(value);
    }
}

Bonus

OK I can’t leave you with just this without providing a little ‘from here’ info. Switching on an enum in Java isn’t ideal since you can add all sorts of information to the enum to minimise the necessity for a glorified if..elseif statement. For this difficulty example, we could add a ‘multiplier’ field that allows code to automatically modify state values based on the selected difficulty. See below:

public enum Difficulty
{
    EASY(0, 0.5f),
    MEDIUM(1, 1.0f),
    HARD(2, 2.0f);

    /**
     * Value for this difficulty
     */
    public final int Value;

    /**
     * Multiplier for difficulty
     */
    public final float DifficultyMultiplier;

    private Difficulty(int value, float multiplier)
    {
        Value = value;
        DifficultyMultiplier = multiplier;
    }
}

So now we’ve added the multiplier to the difficulty, we could use it like so:

enemy.speed = baseSpeed * difficulty.DifficultyMultiplier;
player.speed = baseSpeed / difficulty.DifficultyMultiplier;

This has the added advantage that you can manipulate the global difficulty in a single central place.

Posted by Dan in Guides, Java, 7 comments