Itérer les valeurs enum en utilisant des génériques Java

J’essaie de trouver un moyen de parcourir les valeurs d’une enum en utilisant des génériques. Vous ne savez pas comment faire cela ou si c’est possible.

Le code suivant illustre ce que je veux faire. Notez que le code T.values ​​() n’est pas valide dans le code suivant.

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

Voici comment j’instancier un object Filter:

 Filter filter = new Filter(TimePeriod.ALL); 

L’énumération est définie comme suit:

 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 Ssortingng name; private TimePeriod(Ssortingng name) { this.name = name; } @Override public Ssortingng toSsortingng() { return name; } } 

Je me rends compte que cela n’a aucun sens de copier les valeurs d’un enum dans une liste, mais j’utilise une bibliothèque qui a besoin d’une liste de valeurs en entrée et ne fonctionne pas avec des énumérations.


EDIT 2/5/2010:

La plupart des réponses proposées sont très similaires et suggèrent de faire quelque chose comme ceci:

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

Cela fonctionnerait bien si je pouvais être sûr que selectedOption avait une valeur non nulle. Malheureusement, dans mon cas d’utilisation, cette valeur est souvent nulle, car il existe également un constructeur no-arg Filter () public . Cela signifie que je ne peux pas faire un selectedOption.getClass () sans obtenir un NPE. Cette classe de filtre gère une liste des options disponibles parmi les options sélectionnées. Lorsque rien n’est sélectionné, la méthode selectedOption est nulle.

La seule chose que je peux penser à résoudre est de passer une classe dans le constructeur. Donc quelque chose comme ça:

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

Des idées sur la façon de procéder sans avoir besoin d’un paramètre de classe supplémentaire dans les constructeurs?

C’est un problème difficile en effet. Une des choses à faire est de dire à java que vous utilisez un enum. C’est en déclarant que vous étendez la classe Enum pour vos génériques. Cependant, cette classe n’a pas la fonction values ​​(). Donc, vous devez prendre le cours pour lequel vous pouvez obtenir les valeurs.

L’exemple suivant devrait vous aider à résoudre votre problème:

 public > void enumValues(Class enumType) { for (T c : enumType.getEnumConstants()) { System.out.println(c.name()); } } 

Une autre option consiste à utiliser EnumSet:

 class PrintEnumConsants { static > void foo(Class elemType) { for (E e : java.util.EnumSet.allOf(elemType)) { System.out.println(e); } } enum Color{RED,YELLOW,BLUE}; public static void main(Ssortingng[] args) { foo(Color.class); } } 

Utiliser un casting dangereux:

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

Pour être complet, JDK8 nous donne un moyen relativement clair et concis d’y parvenir sans avoir besoin d’utiliser les values() synthétiques values() dans la classe Enum:

Compte tenu d’une simple énumération:

 private enum TestEnum { A, B, C } 

Et un client de test:

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

Cela va imprimer {A, B, C} :

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

Le code peut être sortingvialement adapté pour récupérer différents éléments ou pour les collecter différemment.

Si vous êtes sûr que selectedOption du constructeur Filter(T selectedOption) n’est pas nul. Vous pouvez utiliser la reflection. Comme ça.

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

J’espère que cela t’aides.

Le problème fondamental est que vous devez convertir un tableau en une liste, non? Vous pouvez faire cela en utilisant un type spécifique (TimePeriod au lieu de T) et le code suivant.

Donc, utilisez quelque chose comme ceci:

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

Maintenant, vous pouvez passer la liste dans n’importe quelle méthode qui veut une liste.

Si vous déclarez le filtre comme

 public class Filter 

puis

 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 Ssortingng name; private TimePeriod(Ssortingng name) { this.name = name; } @Override public Ssortingng toSsortingng() { return name; } public Iterator iterator() { return new Iterator() { 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(); } }; } } 

Et l'utilisation est assez facile:

 public class Filter { private List availableOptions = new ArrayList(); private T selectedOption; public Filter(T selectedOption) { this.selectedOption = selectedOption; Iterator it = selectedOption.iterator(); while(it.hasNext()) { availableOptions.add(it.next()); } } } 

Ci-dessous, un exemple d’une classe de wrapper autour d’un Enum. C’est un peu bizarre, c’est ce dont j’ai besoin:

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

}

Pour obtenir la valeur de l’énumération générique:

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

Notez dans la méthode ci-dessus l’appel à la méthode toSsortingng ().

Et puis définissez l’énumération avec une telle méthode toSsortingng ().

 public enum MyNameEnum { MR("John"), MRS("Anna"); private Ssortingng name; private MyNameEnum(Ssortingng name) { this.name = name; } public Ssortingng toSsortingng() { return this.name; } }