Lets say I have the following java enum
public enum Color {
RED(10),
GREEN(22),
BLUE(33);
private int value;
Color(int value) {
this.value = value;
}
public int intValue() {
return value;
}
}
In order to be able to obtain a color instance by a given integer value I need to add method like this:
public static Color getInstance(int value) {
switch (value) {
case 10: return RED;
case 22: return GREEN;
case 33: return BLUE;
default: throw new IllegalArgumentException("Invalid color value");
}
}
Is it possible this method to be autogenerated from the IDE? (Preferably IntelliJ)?
Instead of repeating the code in every enum, you may implement a central utility method for all kinds of enums with an int value. This is possible since enums can implement interfaces, hence you can define a uniform way of accessing the int value:
public interface IntValued {
int intValue();
}
/** get the particular {@link IntValued} {@code enum} constant. */
public static <T extends Enum<T>&IntValued> T get(Class<T> type, int value) {
return type.cast(GET.get(type).apply(value));
}
private static ClassValue<IntFunction<Enum>> GET = new ClassValue<IntFunction<Enum>>() {
protected IntFunction<Enum> computeValue(Class<?> type) {
return prepare(type);
}
};
// invoked only once per enum type
static IntFunction<Enum> prepare(Class<?> type) {
Enum[] values=type.asSubclass(Enum.class).getEnumConstants();
if(values.length==0) return i -> null;
IntSummaryStatistics s=Arrays.stream(values)
.mapToInt(o -> ((IntValued)o).intValue())
.summaryStatistics();
int min=s.getMin(), max=s.getMax();
if((max-min+1)<s.getCount()*2) {
Enum[] linear=new Enum[max-min+1];
for(Enum e: values) linear[((IntValued)e).intValue()-min]=e;
return i -> i<min||i>max? null: linear[i-min];
}
Map<Integer, Enum> map = Arrays.stream(values).collect(
Collectors.toMap(o -> ((IntValued)o).intValue(), Function.identity()));
return map::get;
}
This uses ClassValue, a JRE provided way of associating custom meta data to a class. ClassValue takes care of invoking the initialization code only once and still allows garbage collection/ class unloading. The code above dynamically determines which lookup structure to use. If the int values of a particular enum type are dense, it uses an array, otherwise it resorts to a Map.
You can use it as follows:
public enum Color implements IntValued {
RED(10),
GREEN(22),
BLUE(33);
private int value;
Color(int value) {
this.value = value;
}
public int intValue() {
return value;
}
}
Color color=get(Color.class, 22);
System.out.println(color);
Note that this solution, unlike generated switch statements, does not break if these int values are changed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With