Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why shouldn't Java enum literals be able to have generic type parameters?

People also ask

Can enum be generic Java?

Enum, Interfaces, and Generics Enum cannot extend a class, but can implement an interface because Java does not support multiple inheritances of classes but multiple implementation of interfaces. The enum is a default subclass of the generic Enum<T> class, where T represents generic enum type.

Can enums have parameters?

You can have methods on enums which take parameters. Java enums are not union types like in some other languages.

Is enum type safe in Java?

The enums are type-safe means that an enum has its own namespace, we can't assign any other value other than specified in enum constants. Typesafe enums are introduced in Java 1.5 Version. Additionally, an enum is a reference type, which means that it behaves more like a class or an interface.

Why is enum thread safe in Java?

This technique is absolutely thread-safe. An enum value is guaranteed to only be initialized once, ever, by a single thread, before it is used.


This has been discussed as of JEP-301 Enhanced Enums, which was withdrawn, regrettably. 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 was struggling with significant issues, which couldn't be resolved: 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;
    }

    ...

}

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.


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.