2013-08-31 2 views
2

중복 코드가 없는지 확인하기 위해 enum의 상태를 확인하고 싶습니다. 예를 들어 아래의 enum을 고려하십시오. 자바 열거 형의 상태를 확인하는 방법은 무엇입니까?

public enum UniqueCodes { 
    A(1), B(2), C(3), D(1); 

    private final int value; 

    static { 
     UniqueCodes[] values = UniqueCodes.values(); 
     Map<Integer, Boolean> map = new HashMap<>(); 
     for (UniqueCodes code : values) { 

      if (map.get(code.value) == null) { 
       map.put(code.value, true); 
      } else { 
       String msg = String.format(
         "%s enum contains a non unique code %s", 
         UniqueCodes.class.getName(), code.value); 
       System.err.println(msg); 

       try { 
        System.exit(-1); 
       } catch(SecurityException e) { 
        System.err.println("Really Bad things are going to happen to the application"); 
        // what can I do here to crash the JVM 
       } 
      } 

     } 
    } 

    private UniqueCodes(int value) { 
     this.value = value; 
    } 

    public int getValue() { 
     return value; 
    } 
} 

할당 100 개 + 코드로 위의 열거를 상상하면 더 열거 정의 중복 값을 포함하지 있는지 확인하려면. 중복 된 값이 발견되면 JVM을 중단시키고 싶지만 그렇게하기 쉽지 않습니다. catch(Throwable e)이 모든 것을 잡을 것이기 때문에 예외를 throw하는 것은 효과가 없습니다.

public class Main { 
    public static void main(String[] args) { 
     try { 
      System.out.println(UniqueCodes.A); 
     } catch(Throwable e) { 
      System.out.println("Invalid Enum exception caught"); 
     } 
    } 
} 

단위 테스트를 작성하여 열거 형 정의가 양호하고 중복 코드가 없음을 증명할 수 있습니다. 그러나 일종의 enum에 고유 한 코드가없는 경우 실행되지 않도록 자체 테스트 및 어리석은 증명을 수행하는 방법이 있습니까?

+3

'catch (Throwable e) {'** ** 절대로 이것을하지 마십시오! – Doorknob

+0

@Doorknob'catch (Throwable e)'는 애플리케이션 서버가 모든 예외 처리기에서 범용 캐치 (catch)로 수행 할 수있는 기능입니다. 열거 형이 중복되면 프로그램을 실패하는 방법을 원합니다. – ams

+0

좋아, 그럼 for (;;) {}'? : P – Doorknob

답변

2

점 몇 :

  1. 이에 대한지도보다 세트를 사용하는 것이 간단합니다.
  2. 클래스의 정적 블록 에서 예외를 throw하면이 클래스의로드를 차단할 것이므로 효과적입니다. 의도적으로 catch하고 첫 번째 오류를 catch (Throwable t)으로 무시하더라도 "잘못된"열거 형을 사용하려고하는 이후 코드는 자발적으로 java.lang.NoClassDefFoundError을 던집니다.

    static { 
        Set<Integer> set = new HashSet<>(); 
        for (UniqueCodes code : values()) { 
         if (!set.add(code.value)) { 
          throw new RuntimeException(String.format(
           "%s enum contains a non unique code %s", 
           UniqueCodes.class.getName(), code.value)); 
         } 
        } 
    } 
    

    P.S.을 다음과 같이

나는 유효성 검사 코드를 작성하는 것 특정 코드에 대해 값이 필요하지 않은 경우 Enum.ordinal()이 있어야하며 정의 된 순서대로 상수의 0부터 시작하는 인덱스를 반환해야합니다.

+0

'IllegalStateException'과 비슷해야합니까? – bsd

+0

@bsd 또는 아마도 AssertionError입니다. – Boann

0

예와 같이 열거 형에 대한 가치가 있는지 모르겠습니다. 열거 형을 하드 코딩하고 있기 때문에 코더가 열거 형을 하드 코딩하지 않았는지 확인할 수 없습니까?

+0

물론 코드가 유일해야하고 코드가 100 개 이상인지 확인하고 싶지는 않습니다. 단위 테스트를하지 않고 작동하는 방법을 찾을 수 있는지 궁금한 점이 있습니다. – ams

+1

이것은 단위 테스트에서 처리해야하는 것과 정확히 일치합니다. 열거 형은 하드 코딩되어 있기 때문에 단위 테스트가 통과되면 명확한 지 알 수 있습니다. 내가 왜 당신이 단위 테스트를해야 할 사건을 처리하기 위해 생산에서 JVM을 충돌 코드를 원할지 모르겠다. – dcsohl

2

이 값이이 같은 고유한지 생성자 검사를하는 것이 가장 간단 할 것 :

A(1), B(2), C(3), D(1); 
// Not initialized until after instances 
private static Set<Integer> set = new HashSet<Integer>(); 
private final int value; 
private UniqueCodes(int value) { 
    // throws NPE 
    if (!set.add(value)) 
     throw new IllegalArgumentException("Duplicate value: " + value); 
    this.value = value; 
} 

하지만 열거와 도전은 정적 필드는 인스턴스 뒤에 표시해야하며, 그렇게 될 때까지 초기화되지 않은 것입니다 이후 모든 생성자가 실행됩니다. 너무 늦게 설정을 사용하면 NPE를 얻게됩니다.

다행히도 해결 방법이 있습니다.

당신은 당신에게 제공하기 위해 Initialization-on-demand holder idiom를 사용할 수있는 인스턴스가 초기화 전에 을 설정 초기화 된 :

public enum UniqueCodes { 
    A(1), B(2), C(3), D(1); 
    private static class Holder { 
     static Set<Integer> set = new HashSet<Integer>(); 
    } 
    private final int value; 
    private UniqueCodes(int value) { 
     if (!Holder.set.add(value)) 
      throw new IllegalArgumentException("Duplicate value: " + value); 
     this.value = value; 
    } 

    public int getValue() { 
     return value; 
    } 
} 

이 작동하는 이유는 전에 모든 정적 필드를 초기화해야합니다 클래스 로더 계약 덕분에 클래스를 사용할 수 있으며 클래스는 처음 사용될 때로드됩니다. Holder 클래스는 먼저 생성자에서 사용되며 그 시점에서 클래스 로더는 집합을 초기화합니다.

열거 형에 액세스 할 때 어떤 현상이 발생하는지 보려면 this link을 참조하십시오.

+0

홀더 전략에 대한 흥미로운 접근 방식. – ams

관련 문제