Unique enum member values

前端 未结 5 1087
星月不相逢
星月不相逢 2021-01-19 14:32

My problem: I want to specify a 1 to 1 connection between two enums. basically:

enum MyEnum{

    ENUM_VALUE_1,
    ENUM_VALUE_2,
    ENUM_VALUE_3,

}

enum          


        
相关标签:
5条回答
  • It sounds like you shouldn't implement this as a runtime check. It can only fail if a developer who has control over the code did some bad changes. Detecting changes that introduce bugs is what tests are for.

    Write a simple test that checks if everything is correct. The other answers already provide some good solutions to check for duplicated enums. Instead of running the application to see if the enum initialisation fails, run the test (I hope you already write and run tests anyway).

    0 讨论(0)
  • 2021-01-19 15:16

    You can use a static block to test your linkage:

    import java.util.HashSet;
    import java.util.Set;
    
    public class EnumTrick {
      enum MyEnum {
        ENUM_VALUE_1, ENUM_VALUE_2, ENUM_VALUE_3,
      }
    
      enum MyOtherEnum {
    
        OTHER_ENUM_VALUE_1(MyEnum.ENUM_VALUE_3), 
        OTHER_ENUM_VALUE_2(MyEnum.ENUM_VALUE_1),
        OTHER_ENUM_VALUE_3(MyEnum.ENUM_VALUE_2), 
        OTHER_ENUM_VALUE_4(MyEnum.ENUM_VALUE_2);
    
    
        private MyEnum pair;
    
        MyOtherEnum(MyEnum pair) {
          this.pair = pair;
    
        }
    
        static {
          Set<MyEnum> usedEnums = new HashSet<MyEnum>();
          for(MyOtherEnum moe : MyOtherEnum.values()){
            if(! usedEnums.add(moe.pair) ){
              throw new IllegalArgumentException(moe.pair + " is already used!");
            }
          }
        }
      }
    
      public static void main(String [] args){
        MyOtherEnum moe = MyOtherEnum.OTHER_ENUM_VALUE_1;
      }
    }
    

    Will throw an exception:

    Exception in thread "main" java.lang.ExceptionInInitializerError
      at EnumTrick.main(EnumTrick.java:35)
    Caused by: java.lang.IllegalArgumentException: ENUM_VALUE_2 is already used!
      at EnumTrick$MyOtherEnum.<clinit>(EnumTrick.java:28)
      ... 1 more
    
    0 讨论(0)
  • 2021-01-19 15:23

    Im a bit confused, by your question. Have you considered using HashSet?

    A HashSet can be used to ensure unique values, then simply add the values used in the HashSet if it returns false the value already exists.

    0 讨论(0)
  • 2021-01-19 15:25

    How about this:

    public enum MyEnum {
    
        ENUM_VALUE_1,
        ENUM_VALUE_2,
        ENUM_VALUE_3,
    
    }
    
    // All enums taken.
    private static final Set<MyEnum> taken = EnumSet.noneOf(MyEnum.class);
    
    enum MyOtherEnum {
    
        OTHER_ENUM_VALUE_1(MyEnum.ENUM_VALUE_3),
        OTHER_ENUM_VALUE_2(MyEnum.ENUM_VALUE_1),
        OTHER_ENUM_VALUE_3(MyEnum.ENUM_VALUE_2),
        OTHER_ENUM_VALUE_4(MyEnum.ENUM_VALUE_2);
    
        private MyEnum pair;
    
        MyOtherEnum(MyEnum pair) {
            if (taken.contains(pair)) {
                throw new IllegalArgumentException("Cannot pair the same MyEnum with two other enums! " + this);
            }
            taken.add(pair);
            this.pair = pair;
        }
    
    }
    
    public void test() {
        System.out.println("Hello: " + MyOtherEnum.OTHER_ENUM_VALUE_4);
    }
    
    0 讨论(0)
  • 2021-01-19 15:30

    I put the "why" aside and try to answer your question:

    Create a static block in MyOtherEnum that performs the check:

    static{
        // This set stores all the used values
        EnumSet<MyEnum> usedValues = EnumSet.noneOf(MyEnum.class);
    
        for(MyOtherEnum e : values()){
            // Value already present in the set?
            if(usedValues.contains(e.pair)) throw ...; // Duplicate 
            usedValues.add(e);
        }
    }
    

    But I have to agree with the comments: Instead of writing this check, you can also simply look at your code :).

    0 讨论(0)
提交回复
热议问题