271

Here's my problem - I'm looking for (if it even exists) the enum equivalent of ArrayList.contains();.

Here's a sample of my code problem:

enum choices {a1, a2, b1, b2};

if(choices.???(a1)}{
//do this
} 

Now, I realize that an ArrayList of Strings would be the better route here but I have to run my enum contents through a switch/case elsewhere. Hence my problem.

Assuming something like this doesn't exist, how could I go about doing it?

1
  • Switch/case with strings is implemented starting from Java 7 Commented May 15, 2016 at 15:33

32 Answers 32

333

Use the Apache commons lang3 lib instead

 EnumUtils.isValidEnum(MyEnum.class, myValue)
Sign up to request clarification or add additional context in comments.

6 Comments

Note for those interested, the underlying implementation that they used is simply the try/catch solution (@since 3.0 @version $Id: EnumUtils.java 1199894 2011-11-09 17:53:59Z ggregory $).
Makes my code simpler, so I don't care if it uses exception for flow control (they really shouldn't)... It'd be nice if they changed that.
Does guava also contain a solution like this?
At this point in time, this should be the accepted answer :-).
|
267

This should do it:

public static boolean contains(String test) {

    for (Choice c : Choice.values()) {
        if (c.name().equals(test)) {
            return true;
        }
    }

    return false;
}

This way means you do not have to worry about adding additional enum values later, they are all checked.

Edit: If the enum is very large you could stick the values in a HashSet:

public static HashSet<String> getEnums() {

  HashSet<String> values = new HashSet<String>();

  for (Choice c : Choice.values()) {
      values.add(c.name());
  }

  return values;
}

Then you can just do: values.contains("your string") which returns true or false.

16 Comments

that's a very poor impl.: Choice.valueOf(test) is what you want (w/ try/catch)
bestsss, this is clearly the most appropriate solution. Throwing an exception to implement a type of exists() method is bad practice. While you may think that your implementation is more efficient due to it not looking O(n), it is in the underlying framework which is not visible. Also using try {} catch adds overhead. Plus, it's just not pretty.
@Jared, definitely valueOf. Just catch your exception and return false. To those who say otherwise, if you look at the implementation, it uses a Map already, and the JDK developers have a much better chance to optimize this. The API throws an exception, which is a debatable practice (instead of returning null), but when you deal with an API that throws an exception, go with it, don't reinvent the wheel.
@jluzwick try/catch overhead is a simple jump instruction when not taken, not using the Exception in the catch block is also optimized. Fearing try/catch cause of loss of performance is a bad practice.
contains() is to be preferred over valueOf() with an exception. Why? Because "exceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary control flow" (Joshua Bloch, "Effective Java").
|
71

You can use Enum.valueOf()

enum Choices{A1, A2, B1, B2};

public class MainClass {
  public static void main(String args[]) {
    Choices day;

    try {
       day = Choices.valueOf("A1");
       //yes
    } catch (IllegalArgumentException ex) {  
        //nope
  }
}

If you expect the check to fail often, you might be better off using a simple loop as other have shown - if your enums contain many values, perhaps builda HashSet or similar of your enum values converted to a string and query that HashSet instead.

6 Comments

I don't think Exception are the best choice in such a case.
Try and Catch should be last resort . Try and Catch are to expensive
relying in runtime exceptions to do business logic, besides expensive, is not as readable. regarding checked exceptions, it's different, because those make part of the business.
This also prevent anyone from turning on broad break on exceptions being thrown to find actual exceptional cases that are being retried. (or at least makes it very annoying to do so). Use exceptions for exceptional cases.
EnumUtils.isValidEnum(MyEnum.class, myValue) uses a similar logic and IMO it does make sense to add a whole library for this trivial task
|
58

If you are using Java 1.8, you can choose Stream + Lambda to implement this:

public enum Period {
    DAILY, WEEKLY
};

//This is recommended
Arrays.stream(Period.values()).anyMatch((t) -> t.name().equals("DAILY1"));
//May throw java.lang.IllegalArgumentException
Arrays.stream(Period.values()).anyMatch(Period.valueOf("DAILY")::equals);

1 Comment

Performance-wise it has same issues as @richard-h's for-loop solution though.
27

Guavas Enums could be your friend

Like e.g. this:

enum MyData {
    ONE,
    TWO
}

@Test
public void test() {

    if (!Enums.getIfPresent(MyData.class, "THREE").isPresent()) {
        System.out.println("THREE is not here");
    }
}

1 Comment

how can i check string (FILE 001.xlsx) FILE001("FILE 001.xlsx"), FILE002("FILE 002.xlsx"), FILE003("FILE 003.xlsx");
19

Even better:

enum choices {
   a1, a2, b1, b2;

  public static boolean contains(String s)
  {
      for(choices choice:values())
           if (choice.name().equals(s)) 
              return true;
      return false;
  } 

};

Comments

17

A couple libraries have been mentioned here, but I miss the one that I was actually looking for: Spring!

There is the ObjectUtils#containsConstant which is case insensitive by default, but can be strict if you want. It is used like this:

if(ObjectUtils.containsConstant(Choices.values(), "SOME_CHOISE", true)){
// do stuff
}

Note: I used the overloaded method here to demonstrate how to use case sensitive check. You can omit the boolean to have case insensitive behaviour.

Be careful with large enums though, as they don't use the Map implementation as some do...

As a bonus, it also provides a case insensitive variant of the valueOf: ObjectUtils#caseInsensitiveValueOf

Comments

17

Java Streams provides elegant way to do that

Stream.of(MyEnum.values()).anyMatch(v -> v.name().equals(strValue))

Returns: true if any elements of the stream match the provided value, otherwise false

Comments

15

You can first convert the enum to List and then use list contains method

enum Choices{A1, A2, B1, B2};

List choices = Arrays.asList(Choices.values());

//compare with enum value 
if(choices.contains(Choices.A1)){
   //do something
}

//compare with String value
if(choices.contains(Choices.valueOf("A1"))){
   //do something
}

2 Comments

This should be the accepted answer. Conversion to list is the cleanest way to do it. It spares the whole (side) discussion about "proper use of exceptions" in Java in the other answers here.
Throw IllegalArgumentException if the value doesn't exist.
14

Few assumptions:
1) No try/catch, as it is exceptional flow control
2) 'contains' method has to be quick, as it usually runs several times.
3) Space is not limited (common for ordinary solutions)

import java.util.HashSet;
import java.util.Set;

enum Choices {
    a1, a2, b1, b2;

    private static Set<String> _values = new HashSet<>();

    // O(n) - runs once
    static{
        for (Choices choice : Choices.values()) {
            _values.add(choice.name());
        }
    }

    // O(1) - runs several times
    public static boolean contains(String value){
        return _values.contains(value);
    }
}

1 Comment

Definitely the best answer on this thread when it comes to performance, came up with the same solution when I wanted to create something performant that doesn't rely on exceptions. This answer should be far higher up in this thread.
7

You can use this

YourEnum {A1, A2, B1, B2}

boolean contains(String str){ 
    return Sets.newHashSet(YourEnum.values()).contains(str);
}                                  

Update suggested by @wightwulf1944 is incorporated to make the solution more efficient.

3 Comments

This implementation is inefficient. This iterates through the enum values to create a new set, then creates a stream, which iterates through the resulting set. This means that a new Set and Stream is created every time the function is called, and using stream() on a set means you are iterating on each element in the set instead of taking advantage of the underlying hashtable which will be faster. To improve this, it is best to cache the created Set and use it's contains() method instead. If you must get a stream, use Arrays.stream() instead.
@SubaruTashiro But which library does contain Sets? It is a nice solution, but not for plain Java.
@BairDev java.util.HashSet<E> from the standard library will work fine. Sets is unnecessary.
3

I don't think there is, but you can do something like this:

enum choices {a1, a2, b1, b2};

public static boolean exists(choices choice) {
   for(choice aChoice : choices.values()) {
      if(aChoice == choice) {
         return true;
      }
   }
   return false;
}

Edit:

Please see Richard's version of this as it is more appropriate as this won't work unless you convert it to use Strings, which Richards does.

8 Comments

but I think the OP wants to test a string?
yeah, haha. This method wouldn't be that effective as we already know choice is in the enums. Your modification is more correct.
If you want to work on some subset of the enums themselves (and not their names), better to look at EnumSet. download.oracle.com/javase/6/docs/api/java/util/EnumSet.html
Perhaps a stupid question, but why isn't the .values() documented at download.oracle.com/javase/6/docs/api/java/lang/Enum.html ?
That's a great question. You're right it doesn't exist in the documentation and it doesn't exist in the Enum source either. I'm assuming it's present in one of the implementations of Enum or there is some JLS rule that allows for it. Also all Collection objects have this, and this can be looked at as a Collection even though it isn't necessarily implementing Collection.
|
2

Why not combine Pablo's reply with a valueOf()?

public enum Choices
{
    a1, a2, b1, b2;

    public static boolean contains(String s) {
        try {
            Choices.valueOf(s);
            return true;
        } catch (Exception e) {
            return false;
        }
}

1 Comment

Please don't. See other, older answer that's equivalent to yours: stackoverflow.com/a/4936872/103412
2
  Set.of(CustomType.values())
     .contains(customTypevalue) 

Comments

2

You can make it as a contains method:

enum choices {a1, a2, b1, b2};
public boolean contains(String value){
    try{
        EnumSet.allOf(choices.class).contains(Enum.valueOf(choices.class, value));
        return true;
    }catch (Exception e) {
        return false;
    }
}

or you can just use it with your code block:

try{
    EnumSet.allOf(choices.class).contains(Enum.valueOf(choices.class, "a1"));
    //do something
}catch (Exception e) {
    //do something else
}

Comments

2

I would just write,

Arrays.stream(Choice.values()).map(Enum::name).collect(Collectors.toList()).contains("a1");

Enum#equals only works with object compare.

3 Comments

Thanks for this. The enum I was working with had a non-conventional way to get the string value of the enum so I had to modify your answer like this: Arrays.stream(EventNames.values()).map(EventNames::getEvent) .collect(Collectors.toList()).contains(aString); EventNames is the name of the enum while getEvent() is what returns the associated string value of each enum member.
@MattCampbell if it works, then upvote would be helpful.
works flawlessly!
1

This approach can be used to check any Enum, you can add it to an Utils class:

public static <T extends Enum<T>> boolean enumContains(Class<T> enumerator, String value)
{
    for (T c : enumerator.getEnumConstants()) {
        if (c.name().equals(value)) {
            return true;
        }
    }
    return false;
}

Use it this way:

boolean isContained = Utils.enumContains(choices.class, "value");

Comments

1

This one works for me:

Arrays.asList(YourEnum.values()).toString().contains("valueToCheck");

1 Comment

Your version will return true even if YourEnum contains "valueToCheckBlaBla", because "valueToCheck" will be present in the string representation of the whole list.
1

I created the next class for this validation

public class EnumUtils {

    public static boolean isPresent(Enum enumArray[], String name) {
        for (Enum element: enumArray ) {
            if(element.toString().equals(name))
                return true;
        }
        return false;
    }

}

example of usage :

public ArrivalEnum findArrivalEnum(String name) {

    if (!EnumUtils.isPresent(ArrivalEnum.values(), name))
        throw new EnumConstantNotPresentException(ArrivalEnum.class,"Arrival value must be 'FROM_AIRPORT' or 'TO_AIRPORT' ");

    return ArrivalEnum.valueOf(name);
}

Comments

1

If you are Using Java 8 or above, you can do this :

boolean isPresent(String testString){
      return Stream.of(Choices.values()).map(Enum::name).collect(Collectors.toSet()).contains(testString);
}

Comments

1

EnumUtils.isValidEnum might be the best option if you like to import Apache commons lang3. if not following is a generic function I would use as an alternative.

private <T extends Enum<T>> boolean enumValueExists(Class<T> enumType, String value) {
    boolean result;
    try {
        Enum.valueOf(enumType, value);
        result = true;
    } catch (IllegalArgumentException e) {
        result = false;
    }
    return result;
}

And use it as following

if (enumValueExists(MyEnum.class, configValue)) {
    // happy code
} else {
    // angry code
}

Comments

0

You can use valueOf("a1") if you want to look up by String

3 Comments

but that is not elegant.. if the value does not exist it throws up an exception. so you must probably surround it with try catch
That will throw an exception if the value doesn't exist
Less elegant than iterating through the enum choices looking for a matching object?
0

It is an enum, those are constant values so if its in a switch statement its just doing something like this:

case: val1
case: val2

Also why would you need to know what is declared as a constant?

3 Comments

This bit of code isn't in said switch statement, that's elsewhere. I was simply stating that in this case, enum is necessary as others had suggested that I use an ArrayList instead.
@Jared that makes far more sense now
@Jared however that doesn't really matter as you already know the values that are there. Basically the enum equivalent of list.contains() is MyEnum.MyAwesomeValue
0

With guava it's even simpler:

boolean isPartOfMyEnum(String myString){

return Lists.newArrayList(MyEnum.values().toString()).contains(myString);

}

2 Comments

As kioria said this won't work. MyEnum.values() returns array of MyEnum instances and MyEnum.value().toString() returns string representation of this array object (just string like "[LMyEnum;@15b94ed3")
You need to call .name() instead of .toString() (unless you override the default toString method). See this for more info: Difference between enum .name() and .toString()
0

This combines all of the approaches from previous methods and should have equivalent performance. It can be used for any enum, inlines the "Edit" solution from @Richard H, and uses Exceptions for invalid values like @bestsss. The only tradeoff is that the class needs to be specified, but that turns this into a two-liner.

import java.util.EnumSet;

public class HelloWorld {

static enum Choices {a1, a2, b1, b2}

public static <E extends Enum<E>> boolean contains(Class<E> _enumClass, String value) {
    try {
        return EnumSet.allOf(_enumClass).contains(Enum.valueOf(_enumClass, value));    
    } catch (Exception e) {
        return false; 
    }
}

public static void main(String[] args) {
    for (String value : new String[] {"a1", "a3", null}) {
        System.out.println(contains(Choices.class, value));
    }
}

}

Comments

0
com.google.common.collect.Sets.newHashSet(MyEnum.values()).contains("myValue")

Comments

0

solution to check whether value is present as well get enum value in return :

protected TradeType getEnumType(String tradeType) {
    if (tradeType != null) {
        if (EnumUtils.isValidEnum(TradeType.class, tradeType)) {
            return TradeType.valueOf(tradeType);
        }
    }
    return null;
}

Comments

0

you can also use : com.google.common.base.Enums

Enums.getIfPresent(varEnum.class, varToLookFor) returns an Optional

Enums.getIfPresent(fooEnum.class, myVariable).isPresent() ? Enums.getIfPresent(fooEnum.class, myVariable).get : fooEnum.OTHERS

Comments

0

While iterating a list or catching an exception is good enough for most cases I was searching for something reusable that works well for large enums. In it end, I end up writing this:

public class EnumValidator {

    private final Set<String> values;

    private EnumValidator(Set<String> values) {
        this.values = values;
    }

    public static <T extends Enum<T>> EnumValidator of(Class<T> enumType){
        return new EnumValidator(Stream.of(enumType.getEnumConstants()).map(Enum::name).collect(Collectors.toSet()));
    }

    public boolean isPresent(String et){
        return values.contains(et);
    }
    
}

Comments

0

Java 8+ stream + set way:

    // Build the set.
    final Set<String> mySet = Arrays//
      .stream(YourEnumHere.values())//
      .map(Enum::name)//
      .collect(Collectors.toSet());

    // Reuse the set for contains multiple times.
    mySet.contains(textA);
    mySet.contains(textB);
    ...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.