74 votes

Pourquoi ne puis-je pas utiliser foreach sur une énumération Java ?

Pourquoi je ne peux pas le faire :

Enumeration e = ...
for (Object o : e)
  ...

4 votes

L'énumération a été remplacée par l'Iterator dans Java 1.2 en 1998 et est conservée pour des raisons d'héritage. La vraie question est de savoir pourquoi vous voulez l'utiliser. Peut-être parce que vous utilisez une bibliothèque qui vous oblige à le faire ?

2 votes

@Peter - oui, une bibliothèque externe est la solution.

65voto

cletus Points 276888

Parce que Enumeration<T> ne s'étend pas Iterable<T> . Voici un exemple de réalisation d'énumérations itérables .

Quant à savoir pourquoi, c'est une question intéressante. Ce n'est pas exactement votre question mais cela l'éclaire un peu. De la FAQ sur la conception de l'API Java Collections :

Pourquoi Iterator n'étend-il pas Enumeration ?

Nous considérons les noms de méthodes pour Enumeration comme malheureux. Ils sont très longs, et très fréquemment utilisés. Étant donné que nous avons ajouté une méthode et créer un tout nouveau cadre, nous avons pensé qu'il serait stupide de ne pas de ne pas profiter de l'occasion pour d'améliorer les noms. Bien sûr, nous pourrions supporter les nouveaux et anciens noms dans Iterator, mais cela ne semble pas intéressant.

Cela me laisse penser que Sun veut prendre ses distances par rapport à Enumeration, qui est un des premiers Java avec une syntaxe assez verbeuse.

23 votes

Question suivante : pourquoi les énumérations ne sont-elles pas itérables ? stackoverflow.com/questions/27240/

1 votes

Y a-t-il une différence sémantique entre les deux ? (Je ne suis pas familier avec la classe Iterable) ? Pourquoi ne pas travailler également sur l'énumération ?

4 votes

Parce que les énumérations sont plus proches des Iterator, et non des Iterable (voir la question que mmyers a postée sur stackoverflow). Comme solution de contournement, vous pouvez faire for(; e.hasMoreElements(); ) { e.getNextElement(); }

48voto

user1555669 Points 41

En utilisant la classe utilitaire Collections, l'énumération peut être rendue itérable comme suit :

Enumeration headerValues=request.getHeaders("mycustomheader");
List headerValuesList=Collections.list(headerValues);

for(Object headerValueObj:headerValuesList){
 ... do whatever you want to do with headerValueObj
}

4 votes

Les éléments sont copiés dans une nouvelle liste avant de commencer l'itération, cette solution doit être évitée pour les longues énumérations. Les solutions transformant une énumération en un itérateur ont moins d'impact sur la mémoire.

0 votes

@EmmanuelBourg mais ils ont des effets secondaires, car les énumérations sont stateful.

1 votes

C'est de loin la réponse la plus simple ! Pas de dépendances nécessaires, et clairement lisible. Merci !

8voto

Lawrence Dol Points 27976

J'ai résolu ce problème avec deux classes très simples, une pour Enumeration et un pour Iterator . Le wrapper d'énumération est le suivant :

static class IterableEnumeration<T>
extends Object
implements Iterable<T>, Iterator<T>
{
private final Enumeration<T>        enumeration;
private boolean                     used=false;

IterableEnumeration(final Enumeration<T> enm) {
    enumeration=enm;
    }

public Iterator<T> iterator() {
    if(used) { throw new IllegalStateException("Cannot use iterator from asIterable wrapper more than once"); }
    used=true;
    return this;
    }

public boolean hasNext() { return enumeration.hasMoreElements(); }
public T       next()    { return enumeration.nextElement();     }
public void    remove()  { throw new UnsupportedOperationException("Cannot remove elements from AsIterator wrapper around Enumeration"); }
}

qui peut être utilisé soit avec une méthode utilitaire statique (ce qui est ma préférence) :

/**
 * Convert an `Enumeration<T>` to an `Iterable<T>` for a once-off use in an enhanced for loop.
 */
static public <T> Iterable<T> asIterable(final Enumeration<T> enm) {
    return new IterableEnumeration<T>(enm);
    }

...

for(String val: Util.asIterable(enm)) {
    ...
    }

ou en instanciant la classe :

for(String val: new IterableEnumeration<String>(enm)) {
    ...
    }

4voto

Laurence Gonsalves Points 50783

Le nouveau style de boucle-for ("foreach") fonctionne sur les tableaux, et les éléments qui implémentent la fonction Iterable interface.

C'est aussi plus analogue à Iterator que de Iterable Il n'y aurait donc pas de sens à ce que Enumeration pour travailler avec foreach sauf si Iterator l'a fait aussi (et ce n'est pas le cas). Enumeration est également déconseillé en faveur de Iterator .

2 votes

Soyons prudents avec les termes utilisés ici. La dépréciation signifie quelque chose de très spécifique lorsqu'on parle d'API. L'utilisation de l'énumération est découragée, mais c'est pas déprécié.

0 votes

Ykaganovich : bon point. J'ai corrigé le texte dans la réponse.

1voto

Emmanuel Bourg Points 4555

Enumeration ne met pas en œuvre Iterable et en tant que tel, il ne peut pas être utilisé directement dans une boucle foreach. Cependant, en utilisant Collections Apache Commons il est possible d'itérer sur une énumération avec :

for (Object o : new IteratorIterable(new EnumerationIterator(e))) {
    ...
}

Vous pouvez également utiliser une syntaxe plus courte avec Collections.list() mais cette méthode est moins efficace (deux itérations sur les éléments et plus de mémoire utilisée) :

for (Object o : Collections.list(e))) {
    ...
}

0 votes

Voulez-vous dire IteratorIterable ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X