int 값과 관련된 열거 형 가져 오기


89

이전에는 LegNo 열거 형을 다음과 같이 간단히 정의했습니다.

NO_LEG, LEG_ONE, LEG_TWO

를 호출 return LegNo.values()[i];하여 각 열거 형과 관련된 값을 가져올 수있었습니다.

하지만 이제 LegNo열거 형 NO_LEG을 0 대신 int -1로 지정 했으므로 개인 생성자를 사용하여 int 값을 초기화하고 설정하기로 결정했습니다.

NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

private LegNo(final int leg) { legNo = leg; }

이제 유일한 것은 내가 이런 식으로하기 때문에 values()메소드가 NO_LEG열거 형에 대해 작동하지 않는다는 것입니다 . int와 관련된 열거 형을 어떻게 얻습니까? case switch 문 또는 if-elseif-elseif를 사용하는 것 외에 이것을 수행하는 효율적인 방법이 있습니까?

열거 형에서 int 값을 얻는 것과 관련된 많은 질문을 볼 수 있지만 그 반대입니다.

답변:


148

2018 년 8 월 수정

오늘 나는 이것을 다음과 같이 구현할 것입니다.

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private final int value;

    LegNo(int value) {
        this.value = value;
    }

    public static Optional<LegNo> valueOf(int value) {
        return Arrays.stream(values())
            .filter(legNo -> legNo.value == value)
            .findFirst();
    }
}

열거 형 내부에 매핑을 유지해야합니다.

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private int legNo;

    private static Map<Integer, LegNo> map = new HashMap<Integer, LegNo>();

    static {
        for (LegNo legEnum : LegNo.values()) {
            map.put(legEnum.legNo, legEnum);
        }
    }

    private LegNo(final int leg) { legNo = leg; }

    public static LegNo valueOf(int legNo) {
        return map.get(legNo);
    }
}

정적 블록은 한 번만 호출되므로 여기에는 성능 문제가 거의 없습니다.

편집 : valueOf다른 Java 클래스와 더 인라인으로 메서드 이름을 변경했습니다 .


내가 충분히 명확했는지 확실하지 않아서 죄송합니다. 나는 int를 전달하고 그와 관련된 열거 형을 얻고 싶습니다.
L-Samuels 2012-06-15

@ L-Samuels 질문을 제대로 읽지 않은 것 같아요. 내 업데이트를 참조하십시오.
adarshr

2
나는 이것이 명백해 보인다는 것을 알고 있지만 다음과 같이 사용하십시오 LegNo foo = LegNo.valueOf(2);. 이전 코드는 LegNo.LEG_TWO.
FirstOne 2017

1
반환합니다 (매핑되지 않음) 잘못된 정수 값을 전달, 주목해야합니다 null사용하여 예상대로 HashMap.get을 : 반환 지정된 키가 매핑되는 값 또는 null이지도는 키의 매핑이 포함되지 않는 경우.
FirstOne 2017-11-23

스트림 구문은 깔끔하지만 정적 맵보다 시간 복잡성이 더 높다는 점을 지적 할 가치가 있습니다. 3 개의 값에 대한 문제는 아니지만 valueOf()다른 루프 내부에 1000 개 멤버 열거 형을 사용하는 경우 확실히 문제가됩니다 .
Patrick M

24

모든 멤버를 반복하고 올바른 멤버를 반환하는 정적 메서드를 열거 형에 포함 할 수도 있습니다.

public enum LegNo {
   NO_LEG(-1),
   LEG_ONE(1),
   LEG_TWO(2);

   private int legIndex;

   private LegNo(int legIndex) { this.legIndex = legIndex; }

   public static LegNo getLeg(int legIndex) {
      for (LegNo l : LegNo.values()) {
          if (l.legIndex == legIndex) return l;
      }
      throw new IllegalArgumentException("Leg not found. Amputated?");
   }
}

이제 정수로 Enum 값을 얻으려면 다음을 사용하십시오.

int myLegIndex = 1; //expected : LEG_ONE
LegNo myLeg = LegNo.getLeg(myLegIndex);

나는 이것이 if else if 문을 사용하는 것보다 더 우아하다고 생각합니다. 그러나 더 많은 열거 형 검색이 있다면 @adarshr가 제안한 맵 전략이 더 좋을 것입니다. 유머를 위해 투표하지만.
L-Samuels

1
나도지도 전략을 많이 좋아합니다. 특히 열거 형에 많은 값이 있거나이 메커니즘을 통해 매우 자주 조회해야하는 경우. 그러나 연결된 int로 값을 찾는 것이 상대적으로 드물거나 동일한 조회 요구 사항을 가진 여러 열거 형이있는 경우 맵에 대한 오버 헤드가 절약되므로 내 방식이 더 리소스 친화적 일 것이라고 생각합니다. 또한 코드가 덜 복잡하다는 것을 알았습니다. 그래도 맵 유형으로 확실히 전환 할 몇 가지 사용 사례가 있습니다.
Mike Adler

서수로 연결된 열거 형 값을 파생해서는 안됩니다. 정적 맵 사용은 Java 설계자가 권장하는 방법입니다.
hfontanez

legIndex 필드는이 예제의 서수와 일치하지만 모든 int 값이 될 수 있습니다. 서수 조회가 수행되지 않습니다. 또한 서수 조회가 나쁘다고 생각하는 이유를 제공하거나 링크하십시오.
Mike Adler

1
"다리를 찾을 수 없습니다. 절단 되었습니까?"
Gnagy

17

Java 8에 적용된 adarshr의 답변 :

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;

import java.util.Map;

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private final int legNo;

    private final static Map<Integer, LegNo> map =
            stream(LegNo.values()).collect(toMap(leg -> leg.legNo, leg -> leg));

    private LegNo(final int leg) {
        legNo = leg;
    }

    public static LegNo valueOf(int legNo) {
        return map.get(legNo);
    }
}

11

enum LegNo에서 values ​​() 메서드를 호출하여 주어진 정수 값에 해당하는 Enum 값에 액세스 할 수도 있습니다. LegNo 열거 형의 필드를 반환합니다. LegNo.values()[0]; //returns LEG_NO LegNo.values()[1]; //returns LEG_ONE LegNo.values()[2]; //returns LEG_TWO

그가 찾던 것이 정확히는 아니지만 꽤 가깝고 실제로 매우 간단합니다. (피험자가 죽었더라도 다른 사람에게 유용 할 수 있습니다.)


6

기본값을 사용하는 Java 8 방식 :

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private final int legNo;

    LegNo(int legNo) {
        this.legNo = legNo;
    }

    public static LegNo find(int legNo, Supplier<? extends LegNo> byDef) {
        return Arrays.asList(LegNo.values()).stream()
                .filter(e -> e.legNo == legNo).findFirst().orElseGet(byDef);
    }
}

전화 :

LegNo res = LegNo.find(0, () -> LegNo.NO_LEG);

또는 예외 :

LegNo res = LegNo.find(0, () -> {
    throw new RuntimeException("No found");
});

2
public enum LegNo {

  NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

  private final int code;

  LegNo(int code) {
    this.code = code;
    ReverseStorage.reverseMap.put(code, this);
  }

  public static Optional<LegNo> getByCode(int code) {
    return Optional.ofNullable(ReverseStorage.reverseMap.get(code));
  }

  private static final class ReverseStorage {
    private static final Map<Integer, LegNo> reverseMap = new LinkedHashMap<>();
  }
}

1

열거 형에는 3 개의 요소 만 포함되어 있으므로 가장 빠른 방법은 if else제안한대로 일련의를 사용하는 것입니다.

편집 : adarshr가 제공 한 대답은 열거 형 값이 많은 일반적인 경우에 더 적합하지만 문제에 대해서는 과잉이라고 생각합니다.


갖는 Map코드에서 확실히 잔인한 아니다. 게다가이 방법은 if-else 조건의 스파게티보다 훨씬 더 깨끗합니다.
adarshr

Enum 값이 많으면 Map이 더 좋다는 데 동의하지만 3 개의 값에 대해서는 if / else 구문을 고수합니다. 맛의 문제라고 생각합니다.
DieterDP

어떤 접근 방식을 선택하든 메서드 시그니처를 public LegNo valueOf(int value)변경해서는 안됩니다. 그러면 if-else는 열거 형 자체 내에 작성 될 수 있습니다. if-else가 열거 형에서 벗어나면 확실히 깨끗하지 않은 코드가됩니다.
adarshr

1
나는 :) 완전히 동의
DieterDP

1
public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private int legNo;

    private LegNo(int leg) { legNo = leg; }

    public static LegNo valueOf(int legNo) {
        for (LegNo leg : LegNo.values()) {
            if (leg.legNo == legNo) return leg;
        }   
    }
}

assert LegNo.valueOf(2) == LegNo.LEG_TWO
assert LegNo.valueOf(3) == null

4
룩업 때문에 복잡도 O (N)의 열거 된 값들의 다수에 대한 완전히 무효로 열거 <10 개 값이지만 허용
Alfishe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.