web-dev-qa-db-fra.com

Pourquoi ne puis-je pas utiliser foreach sur Java Enumeration?

Pourquoi je ne peux pas faire:

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

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.

60
cletus

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
}
40
user1555669

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)) {
    ...
    }
6
Lawrence Dol

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.

3
Laurence Gonsalves

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"
});
1
slartidan

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))) {
    ...
}
1
Emmanuel Bourg

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.

0
Stroboskop