2009-08-06 10 views
56

Por qué no puedo hacer:¿Por qué no puedo usar foreach en Java Enumeration?

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

Enumeración fue reemplazado por Iterator en Java 1.2 en 1998 y se conserva para soporte heredado. La verdadera pregunta es por qué quieres usarla. ¿Posiblemente porque usas una biblioteca que te obliga a hacerlo? –

+1

@Peter: sí, una biblioteca externa es la respuesta. – ripper234

Respuesta

55

Debido Enumeration<T> no se extiende Iterable<T>. Aquí hay un example of making Iterable Enumerations.

cuanto a por qué eso es una pregunta interesante. Esta no es exactamente su pregunta, pero arroja algo de luz sobre ella. Desde el Java Collections API Design FAQ:

¿Por qué no se extienden iterador enumeración?

Vemos los nombres de métodos para Enumeración como desafortunado. Son muy largos, y se usan con mucha frecuencia. dado que estábamos añadiendo un método y crear un marco completamente nuevo, que sentimos que sería absurdo no aprovechar la oportunidad de mejorar las nombres. Por supuesto, podríamos apoyar a los nuevos y viejos nombres en iterador, pero no parece que vale la pena .

Eso básicamente me sugiere que Sun quiere distanciarse de la enumeración, que es muy temprano Java con una sintaxis bastante detallado.

+14

Siguiente pregunta: ¿por qué las enumeraciones no se pueden modificar? http://stackoverflow.com/questions/27240/why-arent-enumerations-iterable –

+1

¿Hay una diferencia semántica entre los dos? (No estoy familiarizado con la clase Iterable)? ¿Por qué no tener también trabajo en Enumeration? – ripper234

+4

Porque las enumeraciones son más parecidas a Iterator, no Iterable (vea la pregunta de stackoverflow publicada por mmyers). Como solución alternativa, puede hacer 'for (; e.hasMoreElements();) {e.getNextElement(); } ' – Tim

3

El new-style-for-loop ("foreach") funciona en arreglos y cosas que implementan la interfaz Iterable.

También es más análogo a Iterator que a Iterable, por lo que no tendría sentido que Enumeration trabajar con foreach menos Iterator también lo hizo (y no lo hace). Enumeration también se desanima a favor de Iterator.

+1

Tengamos cuidado con los términos aquí. La depreciación significa algo muy específico al discutir las API. Se desaconseja el uso de la enumeración, pero no está en desuso. – ykaganovich

+0

ykaganovich: buen punto. He corregido el texto en la respuesta. –

0

Debido a una Enumeration (y la mayoría de las clases derivadas de esta interfaz) no implementa Iterable.

Usted puede tratar de escribir su propia clase contenedora.

+2

No debe escribir un contenedor para Enumeration que lo convierta en un Iterable más de lo que debería crear dicho contenedor para Iterator. Los objetos Iterator y Enumeration son estables con respecto a la iteración. Los Iterables no lo son. –

6

He resuelto este problema con dos clases muy simples, una para Enumeration y otra para Iterator. La envoltura enumeración es el siguiente:

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

que puede ser utilizado ya sea con un método de utilidad estática (que es mi preferencia):

/** 
* 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)) { 
    ... 
    } 

o por crear instancias de la clase:

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

Utilizando la clase de utilidad Colecciones, la enumeración puede hacerse iterable como:

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

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

Los elementos se copian en una nueva lista antes de comenzar la iteración; esta solución debe evitarse para enumeraciones largas. Las soluciones que convierten una Enumeración en un iterador tienen menos sobrecarga de memoria. –

+0

@EmmanuelBourg pero tienen efectos secundarios, ya que las enumeraciones son estables. –

+1

¡Esta es la respuesta más fácil! No se necesitan dependencias y es claramente legible. ¡Gracias! –

1

Enumeration no implementa Iterable y como tal no se puede utilizar directamente en un bucle foreach.Sin embargo, utilizando Apache Commons Collections es posible iterar sobre una enumeración con:

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

También es posible usar una sintaxis más corta con Collections.list() pero esto es menos eficiente (dos iteraciones más de los elementos y más uso de memoria):

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

¿se refiere a [IteratorIterable] (http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/iterators/IteratorIterable.html)? – luckyluke

+0

@luckyluke Sí, gracias. Arreglé el ejemplo. –

Cuestiones relacionadas