I'm coping with some work regarding places where I used some unsafe (no type safety) String or int representations of part of the model., and leveraging Enum and EnumSet best practices.
One particular difficulty is this use case : an Enum where every instance holds an EnumSet of [0..n] of its own sisters.
To strip it down to the essentials I based my question on StyleEnum from Joshua Bloch. So we got an enum of BOLD, ITALIC, UNDERLINE, STRIKETHROUGH.. and let's imagine a B_AND_I which will holds {BOLD, ITALIC}.
Please, do not take great of the meaningless example : in the real system this subSets is built on base of some changing rules loaded @ startup time.
The goal is that once this computing has took place, nothing can change instance particular sub-EnumSet range. So I come with something like this :
public enum StyleEnum {
NONE(0, "none"), BOLD(100, "B"), ITALIC(250, "i"), UNDERLINE(350, "u"), STRIKETHROUGH(9, "b"), B_AND_I(99,"Emphase");
//// Pure dream == private final EnumSet<StyleEnum> complexComputedSubSet = new EnumSet<StyleEnum> ();
//// But not in the jdk
private final EnumSet<StyleEnum> complexComputedSubSet;
private final int intProp;
private final String strLabel;
StyleEnum(int intProp, String strLabel) {
this.intProp = intProp;
this.strLabel = strLabel;
//// option 2 would have been be this
// complexComputedSubSet = EnumSet.of(NONE);
//// But COMPILER :: illegal reference to static field from initializer
}//.... end of constructor
/**
* static initialzer will compute based on some rules a subset of (none) or
* others Enum, a particular enum instance can holds in his bag.
*/
static {
//// at least, as option 3, why not this...
// for (StyleEnum e : EnumSet.allOf(StyleEnum.class)) {
// e.complexComputedSubSet = EnumSet.of(NONE);
// }
//// COMPILER :: cannot assign a value to final variable complexComputedSubSet
// main handling here : at class loading
// compute a set (rules coming from whatever you want or can).
//Once this static class level init is done
// nothing can change the computed EnumSet
// it's getter will always return an unmodifiable computed EnumSet
//.... computing something
}
//....
//getter(){}
//whateverelse(){}
}
As you can see nothing is really pleasant or at least elegant here.
In my dreams :
private final EnumSet<StyleEnum> complexComputedSubSet= new EnumSet<StyleEnum> ();
//..
//static initialzer
static {
EnumSet.allOf(StyleEnum.class).forEach(e-> computeSubSet(e));
//..
}
private static void computeSubSet(StyleEnum instance){
//...
instance.complexComputedSubSet.addAll(someComputedCollection);
}
Et voilà !
Instead of that, all I can do seems to pull away the final on the field
// getting away from the final keyword
private EnumSet<StyleEnum> complexComputedSubSet;
then in theclass' static initializer block loop and instantiate with the (dummy) marker (NONE) introduced only for this (silly) purpose :
for (StyleEnum e : EnumSet.allOf(StyleEnum.class)) {
e.complexComputedSubSet = EnumSet.of(NONE);
}
And only after that compute and store the sub-EnumSet.
So all this pain, -mostly-, just because one can not say " new EnumSet ();" ? There must be some better way ? Can you please point me to the good direction ?