2009-11-23 44 views
14

Estoy intentando reemplazar un ciclo basado en iterador sobre una lista Java con una declaración for-each, pero el código usa en algún punto iterator.hasNext() para verificar si llegó al último elemento en la lista.Java: Alternativa a iterator.hasNext() si usa for-each para recorrer una colección

¿Hay algo similar para la alternativa for-each?

for (Object current : objectList) { 
    if (last-element) 
     do-something-special 
} 
+0

Sería útil saber * por qué * está reemplazando un bucle basado en iterador con un enunciado for-each, especialmente desde (como la mayoría lo ha señalado) el enfoque basado en iteradores que está reemplazando le ofrece la funcionalidad lo está solicitando mientras que el enunciado for-each no. – delfuego

+0

Quería reemplazarlo por la elegancia y brevedad del bucle for-each. Pero como no puede cubrir la funcionalidad existente, estoy renunciando a la idea. – Dan

+0

http://download.oracle.com/javase/1.5.0/docs/guide/language/foreach.html – Bozho

Respuesta

21

para-cada uno es simplemente azúcar sintáctico para la versión iterador y si se comprueba el código de bytes compilado, entonces se dará cuenta de que compilador cambia realmente en la versión iterador.

Con un formulario para cada uno, no puede verificar si tendrá más elementos o no. Simplemente permanezca con el uso explícito de iteradores si necesita esa función.

+4

..o si necesita el método Iterator # remove() (si está implementado en el iterador real) –

+0

... o si necesita conocer el índice actual de una matriz, está iterando sobre –

+0

... esa última parte solo es significativa cuando es una lista o matriz; de lo contrario, necesitas crear e incrementar una i por separado, así que también puedes seguir usando el ciclo foreach. –

0

Si desea quedarse con fines de cada uno tal vez algo como esto:

if (objectList.indexOf(current)==objectList.size()-1) break; 
+0

Eso puede ser bastante caro para listas grandes. – Jorn

+1

Podemos iterar (con for-each) a través de cualquier clase que implemente una interfaz Iterable, no debe ser una lista y no tiene que proporcionar ningún método de indexOf –

1

Por desgracia, la de cada idioma no permite comprobar si un elemento es primero o el último en la lista. Esta es una limitación conocida de para cada bucle. Te sugiero que solo sigas usando el iterador.

Si también puede comprobar si el primer elemento en lugar de la última, por ejemplo, si está haciendo concatenación de cadenas, se puede cambiar a algo como:

boolean first = true; 
for (Element e : list) { 
    if (!first) { 
    //do optional operation 
    } 
    //do other stuff 
    first = false; 
} 

pero yo preferiría usar el iterador .

0
int nElts = objectList.size(); 
int n = 0; 
for (...) { 
    if (++n == nElts) ... 

es lo mejor que se me ocurre.

+3

¿Es mejor que usar un Iterator explícito en el bucle for aunque? Yo diría que es más detallado, menos obvio lo que está sucediendo y tiene una mayor probabilidad de errores lógicos que 'if! Iter.hasNext()'. –

+0

No, estoy de acuerdo en que es una solución horrible. Me retractaría, pero lo dejaré aquí como una advertencia para los demás. –

+2

Otro problema aquí es que supone que tiene una Colección (es decir, tiene un método de tamaño) y que no es costoso llamarla. Puede tener un objeto Iterable general que no proporcione un método de tamaño(). De esa forma, el iterador es el único camino a seguir. –

2

El bucle foreach (o el bucle mejorado for) no tiene las funciones para realizar un seguimiento de qué elemento se está iterando en este momento. No hay forma de averiguar qué índice de Collection se está trabajando o si hay más elementos para procesar en un Iterable.

Dicho esto, una solución que funcionaría es mantener una referencia al objeto que se está iterando en este momento en el bucle foreach.

Al mantener una referencia de lo que se está trabajando en la iteración actual, uno podría mantener la referencia una vez que finalice el ciclo foreach, y lo que quede en la variable será el último elemento.

Esta solución alternativa solo funcionará si-y-solo-si el último elemento es el único elemento que se necesita.

Por ejemplo:

String lastString = null; 

for (String s : new String[] {"a", "b", "c"}) { 
    // Do something. 

    // Keep the reference to the current object being iterated on. 
    lastString = s; 
} 

System.out.println(lastString); 

de salida:

c 
7

Además de la respuesta de Luno:

Iterator<MyClass> it = myCollection.iterator(); 
while(it.hasNext()) { 
    MyClass myClass = it.next(): 
    // do something with myClass 
} 

se traduce en:

for (MyClass myClass:myCollection) { 
    // do something with myClass 
} 
4

Como han dicho otros, esto no es posible.

Solo recuerde que el constructo foreach no es el único y final. Se introdujo para hacer que la tarea más común de realizar las mismas operaciones en cada elemento de una colección sea más simple de indicar.

En su caso, no desea hacer exactamente lo mismo con cada elemento, por lo que un bucle foreach no es la herramienta adecuada para el trabajo. Tratar de "piratearlo" para hacer esto es una tontería, solo use un iterador explícito en un ciclo clásico para.

0

Hay dos casos posibles en los que le gustaría hacer esto.

    Tiene que hacer algo después de que se haya alcanzado el último elemento: en este caso, solo necesita colocar el código fuera del ciclo.

    
        for(Object item:theLinkedList){ 
    
        } 
        System.out.println("something special") 
    
    necesita modificar el último elemento de alguna manera o utilizar información relacionada con el último elemento. En este caso se debe utilizar el ** ** LinkedList para acceder al último elemento

    for(Object item:theLinkedList){ 

    } 
    Object last=theLinkedList.getLast(); 
    System.out.println("last"); 
0

sí se puede, así es como yo lo haría si no desea utilizar la sintaxis explícita iterador:

for (Object current : objectList) { 
    if (objectList.getLast().equals(current)) 
     do-something-special 
} 
+0

Esto puede producir falsos positivos, si la última palabra de la lista aparece más de una vez en la lista, entonces su condición se cumplirá para cada ocurrencia, no solo la última ocurrencia. –

0

Además de bayer tienes que hacerlo un poco diferente porque no hay un método getLast(). Pero en lugar de usarlo, puede usar este objectList.size() - 1.

for (Object current : objectList) { 
    if (objectList.get(objectList.size() - 1).equals(current)) 
     do-something-special 
} 
0

Sólo tiene que guardar bucle de repetición recuento, la muestra:

int loop = 0; 

    for(Item item : items) { 

     if(loop == 0) { 
      //Is First Item 
     } 

     if(loop != items.size()-1) { 
      //Has Next Item 
     } 

     if(loop == items.size()-1) { 
      //Is Last Item 
     } 

     //Must Be Last Statement 
     loop++; 
    } 

Es similar a for(int i = 0; i < items.size(); i++) bucle;

items.size() se utiliza para listas y items.length para matrices;

Cuestiones relacionadas