views:

4269

answers:

5

Given the following java enum:

public enum AgeRange {

   A18TO23 {
     public String toString() {        
      return "18 - 23";
     }
    },
   A24TO29 {
     public String toString() {        
      return "24 - 29";
     }
    },
   A30TO35 {
     public String toString() {        
      return "30 - 35";
     }
    },

}

Is there any way to convert a string value of "18 - 23" to the corresponding enum value i.e. AgeRange.A18TO23 ?

Thanks!

+4  A: 

You could always create a map from string to value - do so statically so you only need to map it once, assuming that the returned string remains the same over time. There's nothing built-in as far as I'm aware.

Jon Skeet
This is a much better way to handle this. The map is then created when the enum is, and operates much faster than iterating an array.
Spencer K
I am considering this method as well, but I have only around 15 values in this enum. Is it still more efficient to create a map?
Walter
Probably not, to be honest. Hash tables are great for large amounts of data, but I suspect comparing 15 values (at worst) will be about as fast as getting the hashcode, finding the right bucket etc.
Jon Skeet
+2  A: 
for (AgeRange ar: EnumSet.allOf(AgeRange)) {
    if (ar.toString().equals(inString)) {
         myAnswer = ar;
         break;
    }
}

Or something like that? Just typed in, haven't run through a compiler. Forgive (comment on) typos...

Or use logic like this to build a map once. Avoid iteration at runtime. Good idea, Jon.

John M
+3  A: 

The class overrides "toString()" - so, to get the reverse operation, you need to override valueOf() to translate the output of toString() back to the Enum values.

public enum AgeRange {

   A18TO23 {
        public String toString() {        
                return "18 - 23";
        }
        public AgeRange valueOf (Class enumClass, String name) {
                return A18T023
        }
    },

    .
    .
    .
}

Buyer beware - uncompiled and untested...

The mechanism for toString() and valueOf() is a documented part of the API

Ken Gentle
Should that second be valueOf method?
iny
[iny] is absolutely correct - edited to reflect.
Ken Gentle
+11  A: 

The best and simple way to do it is like this:

public enum AgeRange {


           A18TO23 ("18-23"),

           A24TO29 ("24-29"),

           A30TO35("30-35");

           private String value;

           AgeRange(String value){
              this.value = value;
           }


           public String toString(){
               return value;
           }

           public AgeRange getByValue(String value){
               AgeRange returnValue = null;
               for (final AgeRange element : EnumSet.allOf(AgeRange.class)) {
                   if (element.toString().equals(value)) {
                       returnValue = element;
                   }
               }
               return returnValue;
           }

}

Then you just need to invoke the getByValue() method with the String input in it.

sakana
I agree that it's nice to put the value in the constructor. For very large enums (and they would really have to be pretty big) it would make sense to use a map.I'd personally return from inside the loop as well, but then I've never been a fan of "return from one place regardless of readability" :)
Jon Skeet
One other point - it would be better to use EnumSet.allOf instead of AgeRange.values() as otherwise you create a new array for every call.
Jon Skeet
I Agree with you Jon Skeet :) Changing...
sakana
Very interesting. A lot of what's happening in the code is new to me. Thanks for the tip!
Walter
Shouldn't it be static?
Guido
A: 

You could try something like the following?

static AgeRange fromString(String range) {
    for (AgeRange ageRange : values()) {
        if (range.equals(ageRange.toString())) {
            return ageRange;
        }
    }
    return null;   
}

Or, as others suggested, using a caching approach:

private static Map<String, AgeRange> map;

private static synchronized void registerAgeRange(AgeRange ageRange) {
    if (map == null) {
        map = new HashMap<String, AgeRange>();
    }
    map.put(ageRange.toString(), ageRange);
}

AgeRange() {
    registerAgeRange(this);
}

static AgeRange fromString(String range) {
    return map.get(range);
}
toolkit