Java enums are great. So are generics. Of course we all know the limitations of the latter because of type erasure. But there is one thing I don\'t understand, Why can\'t I
Becasue "enum" is the abbreviation for enumeration. It's just a set of named constants that stand in place of ordinal numbers to make the code better readable.
I don't see what the intended meaning of a type-parameterized constant could be.
There are other methods in ENUM that wouldn't work. What would MyEnum.values()
return?
What about MyEnum.valueOf(String name)
?
For the valueOf if you think that compiler could make generic method like
public static MyEnum valueOf(String name);
in order to call it like MyEnum<String> myStringEnum = MyEnum.value("some string property")
, that wouldn't work either.
For example what if you call MyEnum<Int> myIntEnum = MyEnum.<Int>value("some string property")
?
It is not possible to implement that method to work correctly, for example to throw exception or return null when you call it like MyEnum.<Int>value("some double property")
because of type erasure.
Because you can't. Seriously. That could be added to the language spec. It hasn't been. It would add some complexity. That benefit to cost means it isn't a high priority.
Update: Currently being added to the language under JEP 301: Enhanced Enums.
This is now being discussed as of JEP-301 Enhanced Enums. The example given in the JEP is, which is precisely what I was looking for:
enum Argument<X> { // declares generic enum
STRING<String>(String.class),
INTEGER<Integer>(Integer.class), ... ;
Class<X> clazz;
Argument(Class<X> clazz) { this.clazz = clazz; }
Class<X> getClazz() { return clazz; }
}
Class<String> cs = Argument.STRING.getClazz(); //uses sharper typing of enum constant
Unfortunately, the JEP is still struggling with significant issues: http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html
The answer is in the question:
because of type erasure
None of these two methods are possible, since the argument type is erased.
public <T> T getValue(MyEnum<T> param);
public T convert(Object);
To realise those methods you could however construct your enum as:
public enum MyEnum {
LITERAL1(String.class),
LITERAL2(Integer.class),
LITERAL3(Object.class);
private Class<?> clazz;
private MyEnum(Class<?> clazz) {
this.clazz = clazz;
}
...
}
Frankly this seems like more of a solution in search of a problem than anything.
The entire purpose of the java enum is to model a enumeration of type instances that share similiar properties in a way that provides consistency and richness beyond that of comparable String or Integer representations.
Take an example of a text book enum. This is not very useful or consistent:
public enum Planet<T>{
Earth<Planet>,
Venus<String>,
Mars<Long>
...etc.
}
Why would I want my different planets to have different generic type conversions? What problem does it solve? Does it justify complicating the language semantics? If I do need this behavior is an enum the best tool to achieve it?
Additionally how would you manage complex conversions?
for Instance
public enum BadIdea<T>{
INSTANCE1<Long>,
INSTANCE2<MyComplexClass>;
}
Its easy enough with String
Integer
to supply the name or ordinal. But generics would allow you to supply any type. How would you manage the conversion to MyComplexClass
? Now your mucking up two constructs by forcing the compiler to know that there are a limited subset of types that can be supplied to generic enums and introducing additional confusion to concept(Generics) that already seems elude a lot of programmers.