More general solution for enums with arbitrary amount of values using maths, varargs and reflection
Enums all have ordinal values starting from 0 to n. So using that knowledge we can sum up all the ordinal values to a total and substract the ordinal values of the provided enums. If we mix in varargs and some reflextion that works for any enum with an arbitrary amount of values.
Better yet, you can compute the sum without iterating through all the values if you want. Since the the sum of the first n natural numbers is given by (n * (n + 1)) / 2.
Therefore the following would work. You could even use varargs to
import java.lang.reflect.InvocationTargetException; import java.util.Arrays; enum MyEnumWith3Values { A, B, C } enum MyEnumWith4Values { A, B, C, D } public class Main { public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { // For enum with 3 values System.out.println(RemainingEnumValue(MyEnumWith3Values.A, MyEnumWith3Values.B)); System.out.println(RemainingEnumValue(MyEnumWith3Values.A, MyEnumWith3Values.C)); System.out.println(RemainingEnumValue(MyEnumWith3Values.C, MyEnumWith3Values.B)); // For enum with 4 values System.out.println(RemainingEnumValue(MyEnumWith4Values.A, MyEnumWith4Values.B, MyEnumWith4Values.C)); } public static <T extends Enum<T>> Enum<T> RemainingEnumValue(T... enumValues) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { if(enumValues.length < 1) throw new IllegalArgumentException("At least one enum value!"); var enumClazz = enumValues[0].getClass(); var valuesMethod = enumClazz.getMethod("values"); var enumAllValues = (Enum<T>[])valuesMethod.invoke(enumClazz); if(enumAllValues.length - 1 != enumValues.length) throw new IllegalArgumentException("You must provide exactly one less then all the available enum values"); var maxEnumValue = enumAllValues.length - 1; var enumOrdinalTotal = (maxEnumValue * maxEnumValue + maxEnumValue) >> 1; var totalProvidedEnums = Arrays.stream(enumValues).map(Enum::ordinal).reduce(0, Integer::sum); return enumAllValues[enumOrdinalTotal - totalProvidedEnums]; } }
Remark on this solution
I've added this solution since I think it's an interesting and different approach which uses a mathematical idea (which I always find interesting).
However, due to reflection and MyEnum.values() calls being involved it's certainly not the most performant solution. It's also not the most straightforward, robust or maintainable version of all the answers here. Lastly, you shouldn't really use ordinal() (See this SO thread as it can cause some problems.
Without reflection and with cached MyEnum.values()
If don't need it to be generic (=> eliminates reflection) and cache the MyEnum.values() call, you could however also make this quite a bit more performant. You'd still be using ordinal() though.
enum MyEnumWith3Values { A, B, C } public class Main { private static MyEnumWith3Values[] cachedEnumValues = MyEnumWith3Values.values(); public static void main(String[] args){ // For enum with 3 values System.out.println(RemainingEnumValue(MyEnumWith3Values.A, MyEnumWith3Values.B)); System.out.println(RemainingEnumValue(MyEnumWith3Values.A, MyEnumWith3Values.C)); System.out.println(RemainingEnumValue(MyEnumWith3Values.C, MyEnumWith3Values.B)); } public static MyEnumWith3Values RemainingEnumValue(MyEnumWith3Values a, MyEnumWith3Values b){ var maxEnumValue = cachedEnumValues.length - 1; var enumOrdinalTotal = (maxEnumValue * maxEnumValue + maxEnumValue) >> 1; var totalProvidedEnums = a.ordinal() + b.ordinal(); return cachedEnumValues[enumOrdinalTotal - totalProvidedEnums]; } }