Pourquoi je ne peux pas faire:
Enumeration e = ...
for (Object o : e)
...
Car Enumeration<T>
ne s'étend pas Iterable<T>
. Voici un exemple de création d'énumérations itératives .
Quant à savoir pourquoi c'est une question intéressante. Ce n'est pas exactement votre question, mais cela la met en lumière. De la FAQ Java Design API Design :
Pourquoi Iterator ne prolonge-t-il pas l'énumération?
Nous considérons les noms de méthode pour l'énumération comme malheureux. Ils sont très longs et très fréquemment utilisés. Étant donné que nous ajoutions une méthode et créons un tout nouveau cadre, nous avons pensé qu'il serait stupide de ne pas profiter de l'occasion pour améliorer les noms. Bien sûr, nous pourrions prendre en charge les nouveaux et anciens noms dans Iterator, mais cela ne semble pas valoir la peine.
Cela me suggère essentiellement que Sun veut se distancier de l'énumération, qui est très tôt Java avec une syntaxe assez verbeuse.
En utilisant la classe utilitaire Collections, l'énumération peut être rendue itérable comme:
Enumeration headerValues=request.getHeaders("mycustomheader");
List headerValuesList=Collections.list(headerValues);
for(Object headerValueObj:headerValuesList){
... do whatever you want to do with headerValueObj
}
J'ai résolu ce problème avec deux classes très simples, une pour Enumeration
et une pour Iterator
. L'encapsuleur 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)) {
...
}
Le nouveau style pour la boucle ("foreach") fonctionne sur les tableaux et les choses qui implémentent l'interface Iterable
.
C'est aussi plus analogue à Iterator
qu'à Iterable
, donc cela n'aurait aucun sens pour Enumeration
de travailler avec foreach à moins que Iterator
ne le fasse aussi (et non). Enumeration
est également déconseillé en faveur de Iterator
.
Avec Java 8 et au-delà, c'est possible:
import Java.util.Collections;
import Java.util.Enumeration;
Enumeration e = ...;
Collections.list(e).forEach(o -> {
... // use item "o"
});
Enumeration
n'implémente pas Iterable
et en tant que tel ne peut pas être utilisé directement dans une boucle foreach. Cependant en utilisant Apache Commons Collections 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 c'est moins efficace (deux itérations sur les éléments et plus d'utilisation de la mémoire):
for (Object o : Collections.list(e))) {
...
}
Parce qu'une énumération (et la plupart des classes dérivées de cette interface) n'implémente pas Iterable.
Vous pouvez essayer d'écrire votre propre classe wrapper.