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