Gili
Gili

Reputation: 90033

How to map a value back to an enum?

Given an enum where each instance is associated with some value:

public enum SQLState
{
  SUCCESSFUL_COMPLETION("00000"),
  WARNING("01000");

  private final String code;
  SQLState(String code)
  {
    this.code = code;
  }
}

How can I construct a Map for efficient reverse look-ups? I tried the following:

public enum SQLState
{
  SUCCESSFUL_COMPLETION("00000"),
  WARNING("01000");

  private final String code;
  private static final Map<String, SQLState> codeToValue = Maps.newHashMap();
  SQLState(String code)
  {
    this.code = code;
    codeToValue.put(code, this); // problematic line
  }
}

but Java complains: Illegal reference to static field from initializer. That is, the static Map is being initialized after all enum values so you cannot reference it from the constructor. Any ideas?

Upvotes: 10

Views: 758

Answers (3)

Sebastien Lorber
Sebastien Lorber

Reputation: 92150

As you are using Guava, i recommend using the following code:

public enum SQLState {

    SUCCESSFUL_COMPLETION("00000"),
    WARNING("01000"),
    ;

    private final String code;
    private SQLState(String code) {
        this.code = code;
    }

    public static final Function<SQLState,String> EXTRACT_CODE = new Function<SQLState,String>() {
        @Override
        public String apply(SQLState input) {
            return input.code;
        }
    };

    public static final Map<String, SQLState> CODE_TO_VALUE = ImmutableMap.copyOf( Maps.uniqueIndex(EnumSet.allOf(SQLState.class), EXTRACT_CODE) );

    public static void main(String[] args) {
        System.out.println( SQLState.CODE_TO_VALUE.get("00000") );
    }

}

This produces as expected: "SUCCESSFUL_COMPLETION"

Using static initializer is nice when you can't init the final variables inline, but in this case, with Guava, you really can, in a functionnal approach with Guava functions.

Furthermode, you make your list immutable in the same time which is nice if you need to expose it publicly

You can also make your list immutable with a static block but you need to fill a temporary list before initializing the final list.


Check the Maps uniqueIndex documentation which is a really cool function of Guava that permits to index any object by any of its attribute. In case many objects are sharing the same attribute value, you can use Multimaps.index which, for each key, will give you a list of objets having this attribute.

Upvotes: 1

mbatchkarov
mbatchkarov

Reputation: 16049

Initialize the static map in static{...} block before the constructor. Look up static initializer blocks.

Upvotes: 0

Puce
Puce

Reputation: 38132

use:

static {
  for (SQLState sqlState : values()){
     codeToValue.put(sqlState.code, sqlState);
  }
}

Upvotes: 13

Related Questions