Iterate enum values ​​using java generics

I am trying to find a way to iterate over enum values ​​using generics. Not sure how to do this or if it is possible.

The following code illustrates what I want to do. Note that the T.values ​​() code is not valid in the following code.

public class Filter<T> { private List<T> availableOptions = new ArrayList<T>(); private T selectedOption; public Filter(T selectedOption) { this.selectedOption = selectedOption; for (T option : T.values()) { // INVALID CODE availableOptions.add(option); } } } 

Here's how I would instantiate a Filter object:

 Filter<TimePeriod> filter = new Filter<TimePeriod>(TimePeriod.ALL); 

The listing is defined as follows:

 public enum TimePeriod { ALL("All"), FUTURE("Future"), NEXT7DAYS("Next 7 Days"), NEXT14DAYS("Next 14 Days"), NEXT30DAYS("Next 30 Days"), PAST("Past"), LAST7DAYS("Last 7 Days"), LAST14DAYS("Last 14 Days"), LAST30DAYS("Last 30 Days"); private final String name; private TimePeriod(String name) { this.name = name; } @Override public String toString() { return name; } } 

I understand that it makes no sense to copy enumeration values ​​to a list, but I use a library that needs a list of values ​​as input and will not work with enumerations.




EDIT 2/5/2010:

Most of the suggested answers are very similar and suggest doing something like this:

 class Filter<T extends Enum<T>> { private List<T> availableOptions = new ArrayList<T>(); private T selectedOption; public Filter(T selectedOption) { Class<T> clazz = (Class<T>) selectedOption.getClass(); for (T option : clazz.getEnumConstants()) { availableOptions.add(option); } } } 

This will work fine if I can be sure that selectedOption has a non-zero value. Unfortunately, in my use case, this value is often null because there is a public Filter () no-arg constructor. This means that I cannot do selectedOption.getClass () without getting an NPE. This filter class manages the list of available options, which is selected from these options. When nothing is selected, Option is set to null.

The only thing I can decide is to actually pass the class in the constructor. So something like this:

 class Filter<T extends Enum<T>> { private List<T> availableOptions = new ArrayList<T>(); private T selectedOption; public Filter(Class<T> clazz) { this(clazz,null); } public Filter(Class<T> clazz, T selectedOption) { this.selectedOption = selectedOption; for (T option : clazz.getEnumConstants()) { availableOptions.add(option); } } } 

Any ideas how to do this without requiring an additional class parameter in the constructors?

+50
java generics enums enumeration
Feb 05 '10 at 8:32
source share
9 answers

This is a really serious problem. One of the things you need to do is tell java that you are using an enumeration. This means that you are extending the Enum class for your generics. However, this class does not have a values ​​() function. Therefore, you need to take a class for which you can get the values.

The following example will help you fix your problem:

 public <T extends Enum<T>> void enumValues(Class<T> enumType) { for (T c : enumType.getEnumConstants()) { System.out.println(c.name()); } } 
+84
Feb 05 '10 at 8:44
source share

Another option is to use EnumSet:

 class PrintEnumConsants { static <E extends Enum <E>> void foo(Class<E> elemType) { for (E e : java.util.EnumSet.allOf(elemType)) { System.out.println(e); } } enum Color{RED,YELLOW,BLUE}; public static void main(String[] args) { foo(Color.class); } } 
+7
Feb 05 2018-10-05T00
source share

Use of unsafe action:

 class Filter<T extends Enum<T>> { private List<T> availableOptions = new ArrayList<T>(); private T selectedOption; public Filter(T selectedOption) { Class<T> clazz = (Class<T>) selectedOption.getClass(); for (T option : clazz.getEnumConstants()) { availableOptions.add(option); } } } 
+4
Feb 05 '10 at 8:48
source share

For completeness, JDK8 gives us a relatively clean and more concise way to achieve this without the need to use synthetic values() in the Enum class:

For a simple listing:

 private enum TestEnum { A, B, C } 

And the test client:

 @Test public void testAllValues() { System.out.println(collectAllEnumValues(TestEnum.class)); } 

This will open {A, B, C} :

 public static <T extends Enum<T>> String collectAllEnumValues(Class<T> clazz) { return EnumSet.allOf(clazz).stream() .map(Enum::name) .collect(Collectors.joining(", " , "\"{", "}\"")); } 

The code can be trivially adapted to retrieve different elements or to be collected in another way.

+2
Sep 22 '15 at 14:40
source share

If you are sure that the selectedOption of the Filter(T selectedOption) constructor Filter(T selectedOption) not null. You can use reflection. Like this.

 public class Filter<T> { private List<T> availableOptions = new ArrayList<T>(); private T selectedOption; public Filter(T selectedOption) { this.selectedOption = selectedOption; for (T option : this.selectedOption.getClass().getEnumConstants() ) { // INVALID CODE availableOptions.add(option); } } } 

Hope this helps.

+1
Feb 05 '10 at 8:48
source share

The root problem is that you need to convert the array to a list, right? You can do this using a specific type (TimePeriod instead of T) and the following code.

So use something like this:

 List<TimePeriod> list = new ArrayList<TimePeriod>(); list.addAll(Arrays.asList(sizes)); 

Now you can pass the list to any method that wants to get the list.

0
Feb 05 2018-10-10T00
source share

If you declare a filter as

 public class Filter<T extends Iterable> 

then

 import java.util.Iterator; public enum TimePeriod implements Iterable { ALL("All"), FUTURE("Future"), NEXT7DAYS("Next 7 Days"), NEXT14DAYS("Next 14 Days"), NEXT30DAYS("Next 30 Days"), PAST("Past"), LAST7DAYS("Last 7 Days"), LAST14DAYS("Last 14 Days"), LAST30DAYS("Last 30 Days"); private final String name; private TimePeriod(String name) { this.name = name; } @Override public String toString() { return name; } public Iterator<TimePeriod> iterator() { return new Iterator<TimePeriod>() { private int index; @Override public boolean hasNext() { return index < LAST30DAYS.ordinal(); } @Override public TimePeriod next() { switch(index++) { case 0 : return ALL; case 1 : return FUTURE; case 2 : return NEXT7DAYS; case 3 : return NEXT14DAYS; case 4 : return NEXT30DAYS; case 5 : return PAST; case 6 : return LAST7DAYS; case 7 : return LAST14DAYS; case 8 : return LAST30DAYS; default: throw new IllegalStateException(); } } @Override public void remove() { throw new UnsupportedOperationException(); } }; } } 

And use is pretty simple:

 public class Filter<T> { private List<T> availableOptions = new ArrayList<T>(); private T selectedOption; public Filter(T selectedOption) { this.selectedOption = selectedOption; Iterator<TimePeriod> it = selectedOption.iterator(); while(it.hasNext()) { availableOptions.add(it.next()); } } } 
0
Feb 05 2018-10-02T00
source share

The following is an example of a wrapper class around Enum. I am a little weird bu - what I need:

 public class W2UIEnum<T extends Enum<T> & Resumable> { public String id; public String caption; public W2UIEnum(ApplicationContext appContext, T t) { this.id = t.getResume(); this.caption = I18N.singleInstance.getI18nString(t.name(), "enum_" + t.getClass().getSimpleName().substring(0, 1).toLowerCase() + t.getClass().getSimpleName().substring(1, t.getClass().getSimpleName().length()), appContext .getLocale()); } public static <T extends Enum<T> & Resumable> List<W2UIEnum<T>> values( ApplicationContext appContext, Class<T> enumType) { List<W2UIEnum<T>> statusList = new ArrayList<W2UIEnum<T>>(); for (T status : enumType.getEnumConstants()) { statusList.add(new W2UIEnum(appContext, status)); } return statusList; } 

}

0
Mar 07 '14 at 8:37
source share

To get the value of a general enumeration:

  protected Set<String> enum2set(Class<? extends Enum<?>> e) { Enum<?>[] enums = e.getEnumConstants(); String[] names = new String[enums.length]; for (int i = 0; i < enums.length; i++) { names[i] = enums[i].toString(); } return new HashSet<String>(Arrays.asList(names)); } 

Note that in the above method, the toString () method is called.

And then define the enumeration using such toString () method.

 public enum MyNameEnum { MR("John"), MRS("Anna"); private String name; private MyNameEnum(String name) { this.name = name; } public String toString() { return this.name; } } 
0
Dec 08 '15 at 10:23
source share



All Articles