256

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?

Michu93
  • 5,058
  • 7
  • 47
  • 80
Jared
  • 4,823
  • 6
  • 23
  • 15

32 Answers32

317

Use the Apache commons lang3 lib instead

 EnumUtils.isValidEnum(MyEnum.class, myValue)
RaphC
  • 3,204
  • 1
  • 11
  • 4
  • 46
    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 $). – jgawrych Nov 17 '14 at 21:27
  • 2
    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. – jpangamarca Dec 20 '16 at 21:31
  • 1
    src - https://github.com/apache/commons-lang/blob/3a818ed6a833f083a2db9bb6804c1bdb43b9b0ec/src/main/java/org/apache/commons/lang3/EnumUtils.java#L89 – muttonUp Oct 25 '17 at 20:44
  • 2
    Does guava also contain a solution like this? – Cypress Frankenfeld Feb 13 '19 at 21:32
  • At this point in time, this should be the accepted answer :-). – Josue Abarca Oct 26 '20 at 20:57
  • how can i check fileName? public enum ModulacaoFilesEnum { FILE001("FILE 001.xlsx"), FILE002("FILE 002.xlsx"), FILE003("FILE 003.xlsx"); @Getter private final String fileName; ModulacaoFilesEnum(String fileName) { this.fileName = fileName; } } – Mateus Nogueira Sep 08 '22 at 18:54
261

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.

Richard H
  • 38,037
  • 37
  • 111
  • 138
  • 17
    that's a very poor impl.: Choice.valueOf(test) is what you want (w/ try/catch) – bestsss Feb 08 '11 at 18:41
  • really? you'd rather throw an exception? Surely not. If the enum gets very big, you could use a map. – Richard H Feb 08 '11 at 18:43
  • The enum is indeed going to become very large (1000+). What would you suggest? – Jared Feb 08 '11 at 18:47
  • 21
    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. – jluzwick Feb 08 '11 at 18:50
  • @Jared: in that case, loop over the enums as I have done above, and stick the string values c.name() into a HashSet. Then you can just call .contains() on the set every time you want to check. – Richard H Feb 08 '11 at 18:55
  • 27
    @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. – Yishai Feb 08 '11 at 18:59
  • 1
    Yes the underlying framework does use HashMap's but does so with a bit more overhead than the example provided by Richard. Also again you have the try {} catch overhead and it not looking pretty. go with your own static method in this case – jluzwick Feb 08 '11 at 19:07
  • `Class.enumConstantDirectory()` uses a HashMap w/ probably less collisions (2x size and .75f load factor), calling values() does `clone` all the enum constants [use static final Enum[] values=values()]. Also usually it's a mistake not to have the constant, since then you have `null` at best. Possibly the constant should have some use, if not - then simple set of String is a better idea. The remark about bad impl was regarding the values() iteration. Using hashmap is ok but still redundant in my understainging. As for exception throw, return false in the catch block as my remark (w/ try/catch) – bestsss Feb 08 '11 at 19:30
  • 2
    @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. – bestsss Feb 08 '11 at 19:33
  • valueOf() is simpler, a single line (maybe four if you include the exception code). Writing your own code to check the values is a severe case of premature optimization. – DJClayworth Feb 08 '11 at 19:41
  • 2
    @bestsss I'll give it to you that using try {} catch in your fashion is optimized and adds negligible overhead BUT using try {} catch in your example is commonly looked at as bad practice, see http://stackoverflow.com/questions/3515618/different-styles-of-flow-of-program . Since we can guarantee the same performance of the internal Java code without introducing any bugs, we should do the above. This is because it is MUCH clearer and cleaner than using try {} catch for program flow. – jluzwick Feb 08 '11 at 19:48
  • @jluzwick, the provided link has a *horrid* accepted answer with supposedly good usage, OOM are never caught like that since they can occur in any single thread running (just calling Lock.lock() can cause it), they are exceptionally evil. But that's not the point. If you need max performance, you should implement some other data structure since java.util.HashMap is not the best in that case (it virtually ensure a cache miss during the lookup). A linear-probe hashmap would be a faster one. In this case I'd still support using `valueOf`, HashSet should be inited w/ the capacity c-tor too – bestsss Feb 08 '11 at 20:05
  • 28
    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"). – james.garriss May 20 '14 at 16:34
  • @james.garriss Sounds nice in theory. However Java is *full* of exception throwing. That's a clear downside of Java and makes Java code so verbose. In my view try/catch is fine here. – Manuel Apr 25 '19 at 11:33
  • Hi @Manuel. It sounds like you're conflating two issues. This is not about how many exceptions are thrown or how verbose the code becomes. This is about the purpose for which you use exceptions. Whether you have few exceptions or many, they should be for handling exceptional conditions; they should not be used for controlling the flow of your application. I commend Bloch's book to you; I think it will help you understand the issue better. – james.garriss Apr 25 '19 at 11:41
  • 2
    @james.garriss The purpose of exceptions in Java is very debatable in my view. `MalformedURLException` when creating a `new URL` is just one of countless examples. Creating a `URL` without `try/catch` even throws a compiler warning. Java is for historic reasons dependent on `try/catch` by design. So saying that `try/catch` should not for used for controlling the application flow seems more a wish than reality. I agree that it should not be used, but then maybe Java is simply the wrong language due to its legacy. – Manuel Apr 25 '19 at 12:07
67

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.

Michu93
  • 5,058
  • 7
  • 47
  • 80
nos
  • 223,662
  • 58
  • 417
  • 506
  • 15
    I don't think Exception are the best choice in such a case. – GokcenG Apr 29 '14 at 08:18
  • 7
    Try and Catch should be last resort . Try and Catch are to expensive – Jesus Dimrix May 11 '14 at 15:52
  • 4
    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. – Luís Soares Jun 01 '15 at 14:25
  • 2
    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. – Nickolay Kondratyev Jan 29 '16 at 00:08
  • 4
    `EnumUtils.isValidEnum(MyEnum.class, myValue)` uses a similar logic and IMO it does make sense to add a whole library for this trivial task – Vikramjit Roy Mar 28 '19 at 09:39
  • 1
    Thumbs up. Objections to this code are actually baseless. – Fran Marzoa Jun 24 '19 at 15:49
57

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);
Hao Ma
  • 711
  • 7
  • 8
  • Performance-wise it has same issues as [@richard-h](https://stackoverflow.com/a/4936895/2750743)'s for-loop solution though. – Klesun Oct 27 '21 at 18:12
26

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");
    }
}
ihebiheb
  • 3,673
  • 3
  • 46
  • 55
disco crazy
  • 31,313
  • 12
  • 80
  • 83
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;
  } 

};
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

BitfulByte
  • 4,117
  • 1
  • 30
  • 40
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
}
Bikram
  • 828
  • 8
  • 21
  • 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. – Manuel May 12 '19 at 12:20
  • 3
    Throw IllegalArgumentException if the value doesn't exist. – mkyong Jul 09 '19 at 14:57
15

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

Sourabh
  • 1,515
  • 1
  • 14
  • 21
12

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);
    }
}
Andrey
  • 853
  • 9
  • 27
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.

greperror
  • 5,156
  • 3
  • 20
  • 29
  • 5
    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. – Subaru Tashiro Nov 17 '17 at 04:52
  • @SubaruTashiro But which library does contain `Sets`? It is a nice solution, but not for plain Java. – BairDev Oct 12 '21 at 09:50
  • @BairDev `java.util.HashSet` from the standard library will work fine. `Sets` is unnecessary. – Subaru Tashiro Oct 18 '21 at 13:08
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.

jluzwick
  • 2,005
  • 1
  • 15
  • 23
  • but I think the OP wants to test a string? – Richard H Feb 08 '11 at 18:38
  • yeah, haha. This method wouldn't be that effective as we already know choice is in the enums. Your modification is more correct. – jluzwick Feb 08 '11 at 18:40
  • 1
    If you want to work on some subset of the enums themselves (and not their names), better to look at EnumSet. http://download.oracle.com/javase/6/docs/api/java/util/EnumSet.html – Yishai Feb 08 '11 at 18:44
  • Perhaps a stupid question, but why isn't the `.values()` documented at http://download.oracle.com/javase/6/docs/api/java/lang/Enum.html ? – Anonym Feb 08 '11 at 18:46
  • 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. – jluzwick Feb 08 '11 at 19:02
  • @Anonym, because values() is a synthetic method created by the JVM as a static method on the specific Enum subclass, it is not a method on the Enum class itself, so it kind of isn't within the scope of Javadoc to create such an entry. – Yishai Feb 08 '11 at 19:04
  • if you can call that method, don't you already know you have a "choices"? – kem Feb 08 '11 at 19:09
  • Yes, I have edited my answer to state that Richard has the correct implementation. I would have changed my implementation to use Strings had Richard not posted the correct version first. – jluzwick Feb 08 '11 at 19:16
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;
        }
}
Black
  • 5,023
  • 6
  • 63
  • 92
Karthik V
  • 1,033
  • 1
  • 14
  • 29
  • Please don't. See other, older answer that's equivalent to yours: https://stackoverflow.com/a/4936872/103412 – Torsten Sep 24 '18 at 14:54
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
}

aqteifan
  • 456
  • 1
  • 5
  • 17
2

I would just write,

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

Enum#equals only works with object compare.

Swadeshi
  • 1,596
  • 21
  • 33
  • 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. – Matt Campbell Feb 11 '21 at 21:13
  • @MattCampbell if it works, then upvote would be helpful. – Swadeshi Jun 01 '21 at 06:24
  • works flawlessly! – Gaurav Oct 17 '22 at 06:50
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");
António Almeida
  • 9,620
  • 8
  • 59
  • 66
1

This one works for me:

Arrays.asList(YourEnum.values()).toString().contains("valueToCheck");
EDiaz
  • 27
  • 3
  • 5
    Your version will return true even if YourEnum contains "valueToCheckBlaBla", because "valueToCheck" will be present in the string representation of the whole list. – Nicko Jul 31 '18 at 09:56
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);
}
Joey
  • 1,436
  • 2
  • 19
  • 33
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);
}
chirag
  • 198
  • 1
  • 3
  • 17
1
  Set.of(CustomType.values())
     .contains(customTypevalue) 
Dmitrii
  • 11
  • 1
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
}
Mubashar
  • 12,300
  • 11
  • 66
  • 95
0

With guava it's even simpler:

boolean isPartOfMyEnum(String myString){

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

}
chaiyachaiya
  • 2,617
  • 18
  • 19
  • 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") – user2137020 Feb 02 '14 at 16:25
  • 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()](http://stackoverflow.com/questions/18031125/what-is-the-difference-between-enum-name-and-enum-tostring) – Gaʀʀʏ Apr 15 '16 at 14:30
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));
    }
}

}

user2910265
  • 844
  • 1
  • 9
  • 15
0
com.google.common.collect.Sets.newHashSet(MyEnum.values()).contains("myValue")
cnmuc
  • 6,025
  • 2
  • 24
  • 29
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;
}
Amar Magar
  • 840
  • 1
  • 11
  • 15
0

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

Amir Afghani
  • 37,814
  • 16
  • 84
  • 124
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?

Woot4Moo
  • 23,987
  • 16
  • 94
  • 151
  • 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 Feb 08 '11 at 18:44
  • @Jared that makes far more sense now – Woot4Moo Feb 08 '11 at 18:46
  • @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 – Woot4Moo Feb 08 '11 at 18:47
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

Rabhi salim
  • 486
  • 5
  • 17
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);
    }
    
}
Liviu Stirb
  • 5,876
  • 3
  • 35
  • 40
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);
    ...
Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
-1
public boolean contains(Choices value) {
   return EnumSet.allOf(Choices.class).contains(value);
}
Anton
  • 5,831
  • 3
  • 35
  • 45
-19

enum are pretty powerful in Java. You could easily add a contains method to your enum (as you would add a method to a class):

enum choices {
  a1, a2, b1, b2;

  public boolean contains(String s)
  {
      if (s.equals("a1") || s.equals("a2") || s.equals("b1") || s.equals("b2")) 
         return true;
      return false;
  } 

};
Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
  • did you mean `s.equals("b1") || s.equals("b2")` ?? – jmj Feb 08 '11 at 18:32
  • 3
    This probably won't be the best way to do it as you'll have to add new `s.equals("xx")` for each enum you add later on. – jluzwick Feb 08 '11 at 18:34
  • 1
    And there's going to be a 1000+ enums. – Jared Feb 08 '11 at 18:53
  • 24
    How do people who suggest *horrible* solutions such as this, get 64K reputation? I hate to think of all the crappy code being slung out there based on this contributors answers – Dexygen Nov 08 '13 at 18:05