Check if enum exists in Java

JavaStringEnumsCompare

Java Problem Overview


Is there anyway to check if an enum exists by comparing it to a given string? I can't seem to find any such function. I could just try to use the valueOf method and catch an exception but I'v been taught that catching runtime exceptions is not good practice. Anybody have any ideas?

Java Solutions


Solution 1 - Java

If I need to do this, I sometimes build a Set<String> of the names, or even my own Map<String,MyEnum> - then you can just check that.

A couple of points worth noting:

  • Populate any such static collection in a static initializer. Don't use a variable initializer and then rely on it having been executed when the enum constructor runs - it won't have been! (The enum constructors are the first things to be executed, before the static initializer.)
  • Try to avoid using values() frequently - it has to create and populate a new array each time. To iterate over all elements, use EnumSet.allOf which is much more efficient for enums without a large number of elements.

Sample code:

import java.util.*;

enum SampleEnum {
    Foo,
    Bar;

    private static final Map<String, SampleEnum> nameToValueMap =
        new HashMap<String, SampleEnum>();
    
    static {
        for (SampleEnum value : EnumSet.allOf(SampleEnum.class)) {
            nameToValueMap.put(value.name(), value);
        }
    }
    
    public static SampleEnum forName(String name) {
        return nameToValueMap.get(name);
    }
}

public class Test {
    public static void main(String [] args)
        throws Exception { // Just for simplicity!
        System.out.println(SampleEnum.forName("Foo"));
        System.out.println(SampleEnum.forName("Bar"));
        System.out.println(SampleEnum.forName("Baz"));
    }
}

Of course, if you only have a few names this is probably overkill - an O(n) solution often wins over an O(1) solution when n is small enough. Here's another approach:

import java.util.*;

enum SampleEnum {
    Foo,
    Bar;

    // We know we'll never mutate this, so we can keep
    // a local copy.
    private static final SampleEnum[] copyOfValues = values();
    
    public static SampleEnum forName(String name) {
        for (SampleEnum value : copyOfValues) {
            if (value.name().equals(name)) {
                return value;
            }
        }
        return null;
    }
}

public class Test {
    public static void main(String [] args)
        throws Exception { // Just for simplicity!
        System.out.println(SampleEnum.forName("Foo"));
        System.out.println(SampleEnum.forName("Bar"));
        System.out.println(SampleEnum.forName("Baz"));
    }
}

Solution 2 - Java

I don't think there's a built-in way to do it without catching exceptions. You could instead use something like this:

public static MyEnum asMyEnum(String str) {
    for (MyEnum me : MyEnum.values()) {
        if (me.name().equalsIgnoreCase(str))
            return me;
    }
    return null;
}

Edit: As Jon Skeet notes, values() works by cloning a private backing array every time it is called. If performance is critical, you may want to call values() only once, cache the array, and iterate through that.

Also, if your enum has a huge number of values, Jon Skeet's map alternative is likely to perform better than any array iteration.

Solution 3 - Java

One of my favorite lib: Apache Commons.

The EnumUtils can do that easily.

Following an example to validate an Enum with that library:

public enum MyEnum {
    DIV("div"), DEPT("dept"), CLASS("class");

    private final String val;

    MyEnum(String val) {
    this.val = val;
    }

    public String getVal() {
    return val;
    }
}


MyEnum strTypeEnum = null;

// test if String str is compatible with the enum 
// e.g. if you pass str = "div", it will return false. If you pass "DIV", it will return true.
if( EnumUtils.isValidEnum(MyEnum.class, str) ){
    strTypeEnum = MyEnum.valueOf(str);
}

Solution 4 - Java

I don't know why anyone told you that catching runtime exceptions was bad.

Use valueOf and catching IllegalArgumentException is fine for converting/checking a string to an enum.

Solution 5 - Java

Based on Jon Skeet answer i've made a class that permits to do it easily at work:

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * This permits to easily implement a failsafe implementation of the enums's valueOf
 * Better use it inside the enum so that only one of this object instance exist for each enum...
 * (a cache could solve this if needed)
 * </p>
 *
 * <p>
 * Basic usage exemple on an enum class called MyEnum:
 *
 *   private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
 *   public static MyEnum failSafeValueOf(String enumName) {
 *       return FAIL_SAFE.valueOf(enumName);
 *   }
 *
 * </p>
 *
 * <p>
 * You can also use it outside of the enum this way:
 *   FailSafeValueOf.create(MyEnum.class).valueOf("EnumName");
 * </p>
 *
 * @author Sebastien Lorber <i>([email protected])</i>
 */
public class FailSafeValueOf<T extends Enum<T>> {

    private final Map<String,T> nameToEnumMap;

    private FailSafeValueOf(Class<T> enumClass) {
        Map<String,T> map = Maps.newHashMap();
        for ( T value : EnumSet.allOf(enumClass)) {
            map.put( value.name() , value);
        }
        nameToEnumMap = ImmutableMap.copyOf(map);
    }

    /**
     * Returns the value of the given enum element
     * If the 
     * @param enumName
     * @return
     */
    public T valueOf(String enumName) {
        return nameToEnumMap.get(enumName);
    }

    public static <U extends Enum<U>> FailSafeValueOf<U> create(Class<U> enumClass) {
        return new FailSafeValueOf<U>(enumClass);
    }

}

And the unit test:

import org.testng.annotations.Test;

import static org.testng.Assert.*;


/**
 * @author Sebastien Lorber <i>(lorber.sebastien@gmail.com)</i>
 */
public class FailSafeValueOfTest {

    private enum MyEnum {
        TOTO,
        TATA,
        ;

        private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
        public static MyEnum failSafeValueOf(String enumName) {
            return FAIL_SAFE.valueOf(enumName);
        }
    }

    @Test
    public void testInEnum() {
        assertNotNull( MyEnum.failSafeValueOf("TOTO") );
        assertNotNull( MyEnum.failSafeValueOf("TATA") );
        assertNull( MyEnum.failSafeValueOf("TITI") );
    }
   
    @Test
    public void testInApp() {
        assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TOTO") );
        assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TATA") );
        assertNull( FailSafeValueOf.create(MyEnum.class).valueOf("TITI") );
    }

}

Notice that i used Guava to make an ImmutableMap but actually you could use a normal map i think since the map is never returned...

Solution 6 - Java

Most of the answers suggest either using a loop with equals to check if the enum exists or using try/catch with enum.valueOf(). I wanted to know which method is faster and tried it. I am not very good at benchmarking, so please correct me if I made any mistakes.

Heres the code of my main class:

	package enumtest;

public class TestMain {

	static long timeCatch, timeIterate;
	static String checkFor;
	static int corrects;

	public static void main(String[] args) {
		timeCatch = 0;
		timeIterate = 0;
		TestingEnum[] enumVals = TestingEnum.values();
		String[] testingStrings = new String[enumVals.length * 5];
		for (int j = 0; j < 10000; j++) {
			for (int i = 0; i < testingStrings.length; i++) {
				if (i % 5 == 0) {
					testingStrings[i] = enumVals[i / 5].toString();
				} else {
					testingStrings[i] = "DOES_NOT_EXIST" + i;
				}
			}

			for (String s : testingStrings) {
				checkFor = s;
				if (tryCatch()) {
					++corrects;
				}
				if (iterate()) {
					++corrects;
				}
			}
		}

		System.out.println(timeCatch / 1000 + "us for try catch");
		System.out.println(timeIterate / 1000 + "us for iterate");
		System.out.println(corrects);
	}

	static boolean tryCatch() {
		long timeStart, timeEnd;
		timeStart = System.nanoTime();
		try {
			TestingEnum.valueOf(checkFor);
			return true;
		} catch (IllegalArgumentException e) {
			return false;
		} finally {
			timeEnd = System.nanoTime();
			timeCatch += timeEnd - timeStart;
		}

	}

	static boolean iterate() {
		long timeStart, timeEnd;
		timeStart = System.nanoTime();
		TestingEnum[] values = TestingEnum.values();
		for (TestingEnum v : values) {
			if (v.toString().equals(checkFor)) {
				timeEnd = System.nanoTime();
				timeIterate += timeEnd - timeStart;
				return true;
			}
		}
		timeEnd = System.nanoTime();
		timeIterate += timeEnd - timeStart;
		return false;
	}
}

This means, each methods run 50000 times the lenght of the enum I ran this test multiple times, with 10, 20, 50 and 100 enum constants. Here are the results:

  • 10: try/catch: 760ms | iteration: 62ms
  • 20: try/catch: 1671ms | iteration: 177ms
  • 50: try/catch: 3113ms | iteration: 488ms
  • 100: try/catch: 6834ms | iteration: 1760ms

These results were not exact. When executing it again, there is up to 10% difference in the results, but they are enough to show, that the try/catch method is far less efficient, especially with small enums.

Solution 7 - Java

Since Java 8, we could use streams instead of for loops. Also, it might be apropriate to return an Optional if the enum does not have an instance with such a name.

I have come up with the following three alternatives on how to look up an enum:

private enum Test {
    TEST1, TEST2;

    public Test fromNameOrThrowException(String name) {
        return Arrays.stream(values())
                .filter(e -> e.name().equals(name))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("No enum with name " + name));
    }

    public Test fromNameOrNull(String name) {
        return Arrays.stream(values()).filter(e -> e.name().equals(name)).findFirst().orElse(null);
    }

    public Optional<Test> fromName(String name) {
        return Arrays.stream(values()).filter(e -> e.name().equals(name)).findFirst();
    }
}

Solution 8 - Java

Just use valueOf() method.

If the value doesn't exist, it throws IllegalArgumentException and you can catch it like that:

boolean isSettingCodeValid = true;
try {
    SettingCode.valueOf(settingCode.toUpperCase());
} catch (IllegalArgumentException e) {
    // throw custom exception or change the isSettingCodeValid value
    isSettingCodeValid = false;
}

Solution 9 - Java

You can also use Guava and do something like this:

// This method returns enum for a given string if it exists, otherwise it returns default enum.
private MyEnum getMyEnum(String enumName) {
  // It is better to return default instance of enum instead of null
  return hasMyEnum(enumName) ? MyEnum.valueOf(enumName) : MyEnum.DEFAULT;
}

// This method checks that enum for a given string exists.
private boolean hasMyEnum(String enumName) {
  return Iterables.any(Arrays.asList(MyEnum.values()), new Predicate<MyEnum>() {
    public boolean apply(MyEnum myEnum) {
      return myEnum.name().equals(enumName);
    }
  }); 
}

In second method I use guava (Google Guava) library which provides very useful Iterables class. Using the Iterables.any() method we can check if a given value exists in a list object. This method needs two parameters: a list and Predicate object. First I used Arrays.asList() method to create a list with all enums. After that I created new Predicate object which is used to check if a given element (enum in our case) satisfies the condition in apply method. If that happens, method Iterables.any() returns true value.

Solution 10 - Java

Here is what I use to check if an enum constant with given name exists:

java.util.Arrays.stream(E.values()).map(E::name).toList().contains("");

(Suppose your enum is called E.) Here inside "" you should put a name of an enum constant for which you wish to check if it is defined in the enum or not. This is certainly not the best possible solution since it converts an array into Stream and then again into List, but is nice and short and it works fine for me.

As other people mentioned, since you asked this question in 2009., this will not work in your case (unless you migrated to a newer version of Java) since in 2009. Java did not support features used in this answer. But I am posting anyway in case someone with newer version of Java wants to do this.

Solution 11 - Java

Using java 8, you can do something like the below to check if it is valid.

Stream.of(MyEnum.values())
        .map(MyEnum::name)
        .collect(Collectors.toList()).contains(<STRING_YOU_WANT_TO_VALIDATE>)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDannyView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavaMichael MyersView Answer on Stackoverflow
Solution 3 - JavaрüффпView Answer on Stackoverflow
Solution 4 - JavanosView Answer on Stackoverflow
Solution 5 - JavaSebastien LorberView Answer on Stackoverflow
Solution 6 - JavaAlexander DaumView Answer on Stackoverflow
Solution 7 - JavaMagnilexView Answer on Stackoverflow
Solution 8 - JavansvView Answer on Stackoverflow
Solution 9 - JavaDawid StępieńView Answer on Stackoverflow
Solution 10 - JavaKRISTIJAN TOMASINIView Answer on Stackoverflow
Solution 11 - Javasyed wasim nihalView Answer on Stackoverflow