Java : 열거 형에 지정된 문자열이 포함되어 있는지 확인하십시오.


169

여기 내 문제가 있습니다-열거 형에 해당하는 열거 형을 찾고 있습니다 (존재하는 경우) ArrayList.contains();.

내 코드 문제의 샘플은 다음과 같습니다.

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

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

이제는 ArrayListStrings가 더 나은 경로 있지만 스위치 / 케이스를 통해 열거 형 내용을 실행해야합니다. 따라서 내 문제.

이와 같은 것이 존재하지 않는다고 가정하면 어떻게 할 수 있습니까?


문자열이있는 스위치 / 케이스는 Java 7
AndreyP

답변:


205

이것은해야합니다 :

public static boolean contains(String test) {

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

    return false;
}

이 방법은 나중에 열거 형 값을 추가하는 것에 대해 걱정할 필요가 없으며 모두 확인됩니다.

편집 : 열거 형이 매우 큰 경우 HashSet에 값을 붙일 수 있습니다.

public static HashSet<String> getEnums() {

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

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

  return values;
}

그런 다음 수행 할 수 있습니다 : values.contains("your string")true 또는 false를 반환합니다.


12
그것은 매우 열악한 의미입니다. Choice.valueOf (test)는 당신이 원하는 것입니다 (w / try / catch)
bestsss

17
bestsss, 이것은 분명히 가장 적합한 솔루션입니다. exist () 메서드 유형을 구현하기 위해 예외를 throw하는 것은 좋지 않습니다. O (n)으로 보이지 않기 때문에 구현이 더 효율적이라고 생각할 수도 있지만 보이지 않는 기본 프레임 워크에 있습니다. 또한 try {} catch를 사용하면 오버 헤드가 추가됩니다. 게다가, 그것은 예쁘지 않습니다.
jluzwick

25
@Jared, 확실히 valueOf. 예외를 잡아서 거짓을 반환하십시오. 달리 말하는 사람들에게 구현을 살펴보면 이미 Map을 사용하고 있으며 JDK 개발자는이를 최적화 할 가능성이 훨씬 높습니다. API는 예외를 발생 시키는데, 이는 null을 반환하는 대신 논란의 여지가 있지만 예외를 throw하는 API를 처리 할 때는 예외를 처리해야합니다.
Yishai

2
@jluzwick try / catch 오버 헤드는 취하지 않을 때 간단한 점프 명령이며 catch 블록에서 예외를 사용하지 않는 것도 최적화됩니다. 성능 손실의 원인을 두려워하는 것은 나쁜 습관입니다.
bestsss

22
contains ()는 예외를 제외하고 valueOf ()보다 선호됩니다. 왜? "예외는 그 이름에서 알 수 있듯이 예외적 인 조건에만 사용해야하며 일반적인 제어 흐름에는 사용해서는 안됩니다"(Joshua Bloch, "Effective Java").
james.garriss

226

대신 Apache commons lang3 lib를 사용하십시오.

 EnumUtils.isValidEnum(MyEnum.class, myValue)

33
관심있는 사람들을 위해 그들이 사용한 기본 구현은 단순히 try / catch 솔루션입니다 (@since 3.0 @version $ Id : EnumUtils.java 1199894 2011-11-09 17 : 53 : 59Z ggregory $).
Jonathan Gawrych '11

1
코드를 더 간단하게 만들므로 흐름 제어에 예외를 사용하는지 여부는 신경 쓰지 않습니다 (실제로해서는 안됨) ... 그것이 변경되면 좋을 것입니다.
jpangamarca


1
구아바에도 이와 같은 솔루션이 포함되어 있습니까?
Cypress Frankenfeld

50

당신이 사용할 수있는 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
  }
}

검사가 자주 실패 할 것으로 예상되는 경우, 다른 루프가 보여준 것처럼 간단한 루프를 사용하는 것이 좋습니다. 열거 형에 많은 값이 포함 된 경우 ( 아마도 HashSet열거 형 또는 이와 유사한 열거 형 값이 문자열로 변환되어 HashSet대신 쿼리 됨) .


8
그런 경우에는 예외가 최선의 선택이라고 생각하지 않습니다.
GokcenG

6
시도와 캐치가 최후의 수단이되어야합니다. 시도와 캐치는 비싸다
Jesus Dimrix

2
비싸지 않고 비즈니스 로직을 수행하기 위해 런타임 예외에 의존하는 것은 읽기 쉽지 않습니다. 확인 된 예외와 관련하여 비즈니스의 일부이기 때문에 다릅니다.
Luís Soares 2016 년

2
또한 재시도중인 예외적 인 실제 사례를 찾기 위해 예외가 발생했을 때 모든 사람이 광범위한 중단을 설정하지 못하게합니다. (또는 적어도 그렇게하는 것이 매우 성가시다). 예외적 인 경우에는 예외를 사용하십시오.
Nickolay Kondratyev 님이

4
EnumUtils.isValidEnum(MyEnum.class, myValue)비슷한 논리와 IMO를 사용하여이 사소한 작업을 위해 전체 라이브러리를 추가하는 것이 합리적입니다.
Vikramjit Roy

37

Java 1.8을 사용하는 경우 Stream + Lambda를 선택하여이를 구현할 수 있습니다.

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

19

더 나은 :

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

};

낙관적 인 솔루션을 주셔서 감사합니다
Parth 파텔

19

Guavas Enums 는 당신의 친구가 될 수 있습니다

예를 들면 다음과 같습니다.

enum MyData {
    ONE,
    TWO
}

@Test
public void test() {

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

11

먼저 열거 형을 List로 변환 한 다음 list contains 메소드를 사용할 수 있습니다

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
}

이것이 정답입니다. 목록으로 변환하는 것이 가장 깔끔한 방법입니다. 여기에는 다른 답변에서 Java의 "예외의 올바른 사용"에 대한 전체 토론이 필요하지 않습니다.
Manuel

값이 존재하지 않으면 IllegalArgumentException을 발생시킵니다.
mkyong

10

여기에 몇 개의 라이브러리가 언급되었지만 실제로 찾고 있던 라이브러리가 그리워졌습니다 : Spring!

거기입니다 ObjectUtils # containsConstant 기본적으로 케이스를 구분하지 않습니다,하지만 당신이 원하는 경우에 엄격한 될 수 있습니다. 다음과 같이 사용됩니다 :

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

참고 : 대소 문자를 구분하는 확인을 사용하는 방법을 보여주기 위해 오버로드 된 방법을 사용했습니다. 부울을 생략하여 대소 문자를 구분하지 않는 동작을 수행 할 수 있습니다.

그래도 큰 enum에주의하십시오. 일부처럼 Map 구현을 사용하지 않기 때문에 ...

또한, valueOf의 대소 문자를 구분하지 않는 변형을 제공합니다. ObjectUtils # caseInsensitiveValueOf


9

몇 가지 가정 :
1) 예외적 인 흐름 제어이기 때문에 시도 / 캐치가 없습니다.
2) '포함'방법은 일반적으로 여러 번 실행되므로 신속해야합니다.
3) 공간은 제한되지 않습니다 (일반 솔루션의 경우 일반적 임)

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

7

이것을 사용할 수 있습니다

YourEnum {A1, A2, B1, B2}

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

솔루션의 효율성을 높이기 위해 @ wightwulf1944에서 제안한 업데이트가 통합되었습니다.


4
이 구현은 비효율적입니다. 이렇게하면 열거 값을 반복하여 새 집합을 만든 다음 결과 집합을 반복하는 스트림을 만듭니다. 이것은 함수가 호출 될 때마다 새로운 세트와 스트림이 생성됨을 stream()의미하며, 세트를 사용한다는 것은 기본 해시 테이블을 이용하는 대신 세트의 각 요소를 반복한다는 것을 의미합니다. 이를 개선하려면 생성 된 세트를 캐시하고 contains()대신 메소드를 사용하는 것이 가장 좋습니다. 스트림을 가져와야하는 경우 Arrays.stream()대신 사용하십시오.
스바루 타시로

3

나는 생각하지 않지만 다음과 같이 할 수 있습니다.

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

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

편집하다:

Richards가 수행하는 String을 사용하도록 변환하지 않으면 작동하지 않기 때문에 Richard의 버전이 더 적합하므로 참조하십시오.


OP가 문자열을 테스트하려고한다고 생각합니까?
Richard H

그래, 하하 이 방법은 열거 형에 선택이 있다는 것을 이미 알고 있으므로 효과적이지 않습니다. 수정이 더 정확합니다.
jluzwick

1
열거 형 자체의 일부 하위 집합 (이름이 아닌)을 작업하려면 EnumSet을 보는 것이 좋습니다. download.oracle.com/javase/6/docs/api/java/util/EnumSet.html
Yishai

아마도 어리석은 질문이지만 download.oracle.com/javase/6/docs/api/java/lang/Enum.html에.values() 문서화되어 있지 않은 이유는 무엇입니까?
익명

좋은 질문입니다. 문서에 존재하지 않으며 Enum 소스에도 존재하지 않습니다. Enum 구현 중 하나에 있거나 가정 할 수있는 JLS 규칙이 있다고 가정합니다. 또한 모든 Collection 객체에는 이것이 있으며 Collection을 반드시 구현하지 않아도 Collection으로 볼 수 있습니다.
jluzwick

3

Java Streams는이를위한 우아한 방법을 제공합니다

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

스트림의 요소가 제공된 값과 일치하면 true, 그렇지 않으면 false


2

Pablo의 답장과 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;
        }
}

제발 하지마 당신과 동등한 다른 오래된 대답을보십시오 : stackoverflow.com/a/4936872/103412
Torsten

1

이 접근법은 any를 확인하는 데 사용할 수 있으며 클래스에 Enum추가 할 수 있습니다 Utils.

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

이 방법으로 사용하십시오 :

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

1

이 유효성 검사를 위해 다음 수업을 만들었습니다.

public class EnumUtils {

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

}

사용 예 :

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

0

valueOf("a1")문자열로 조회하려는 경우 사용할 수 있습니다


3
그러나 그것은 우아하지 않습니다. 값이 존재하지 않으면 예외가 발생합니다. 그래서 당신은 아마 그것을 시도 캐치로 둘러싸 야합니다
Kasturi

값이 존재하지 않으면 예외가 발생합니다.
Richard H

일치하는 객체를 찾는 열거 형 선택을 반복하는 것보다 덜 우아합니까?
jprete

0

그것은 열거 형이며, 상수 값이므로 switch 문에 다음과 같은 일을하면됩니다.

case: val1
case: val2

또한 상수로 선언 된 것을 알아야하는 이유는 무엇입니까?


이 코드는 스위치 문에 나와 있지 않습니다. 다른 사람들이 대신 ArrayList를 사용하도록 제안 했으므로이 경우 enum이 필요하다고 간단히 말하고있었습니다.
Jared

@Jared 지금 훨씬 더 의미가 있습니다
Woot4Moo

그러나 @Jared는 이미 존재하는 값을 알고 있으므로 중요하지 않습니다. 기본적으로 list.contains ()에 해당하는 열거 형은 MyEnum.MyAwesomeValue
Woot4Moo

0

구아바를 사용하면 훨씬 간단합니다.

boolean isPartOfMyEnum(String myString){

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

}

으로 kioria는 말했다이 작동하지 않습니다. MyEnum.values()MyEnum 인스턴스의 배열을 MyEnum.value().toString()반환하고이 배열 객체의 문자열 표현을 반환합니다 ( "[LMyEnum; @ 15b94ed3"와 같은 문자열)
user2137020

기본 toString 메서드를 재정의하지 않는 한 .name()대신 호출해야합니다 .toString(). 자세한 내용은 다음을 참조하십시오 : enum .name ()과 .toString ()의
차이점

0

이것은 이전 방법의 모든 접근 방식을 결합하며 동등한 성능을 가져야합니다. 모든 열거 형에 사용할 수 있으며 @Richard H의 "Edit"솔루션에 인라인하고 @bestsss와 같은 유효하지 않은 값에는 예외를 사용합니다. 유일한 단점은 클래스를 지정해야하지만 이것이 두 개의 라이너로 바뀐다는 것입니다.

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

}


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

0

값이 있는지 여부를 확인하는 솔루션은 열거 형 값을 반환합니다.

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

0

이것은 나를 위해 작동합니다 :

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

3
YourEnum에 "valueToCheckBlaBla"가 포함되어 있어도 버전은 true를 반환합니다. "valueToCheck"는 전체 목록의 문자열 표현에 있기 때문입니다.
Nicko

0

Java 8 이상을 사용중인 경우 다음을 수행 할 수 있습니다.

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


0

contains 메소드로 만들 수 있습니다.

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

또는 코드 블록과 함께 사용할 수 있습니다.

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

0

다음을 사용할 수도 있습니다 : com.google.common.base.Enums

Enums.getIfPresent (varEnum.class, varToLookFor)는 Optional을 반환합니다

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


0

난 그냥 쓸거야

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

Enum # equals는 객체 비교에서만 작동합니다.


-1
public boolean contains(Choices value) {
   return EnumSet.allOf(Choices.class).contains(value);
}

작동하지 않습니다. set enum 객체가 있고 문자열을 확인하는 중입니다.
iTake

이제 String에 관한 질문에 대한 답이 맞지 않습니다.
iTake

-11

enumJava에서 매우 강력합니다. contains클래스에 메소드를 추가하는 것처럼 메소드를 열거 형에 쉽게 추가 할 수 있습니다 .

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

};

당신은 의미 했습니까 s.equals("b1") || s.equals("b2")??
Jigar Joshi

3
s.equals("xx")나중에 추가 할 각 열거 형마다 새 항목을 추가해야하므로이 방법이 최선의 방법이 아닐 수도 있습니다 .
jluzwick

1
그리고 1000 개 이상의 열거 형이있을 것입니다.
Jared

20
이와 같은 끔찍한 솔루션 을 제안하는 사람들은 어떻게 64K 평판을 얻습니까? 이 기고자 답변을 기반으로 모든
크 래피
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.