2009-11-23 7 views
14

Je suis en train de remplacer une boucle basée itérateur sur une liste Java avec une déclaration for-each, mais le code utilise à un moment donné iterator.hasNext() pour vérifier s'il a atteint le dernier élément de la liste.Java: Alternative à iterator.hasNext() en cas d'utilisation pour chaque-à boucle sur une collection

Y a-t-il quelque chose de similaire pour l'alternative for-each?

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

Il serait utile de savoir * pourquoi * vous remplacez une boucle basée sur l'itérateur par une instruction for-each, d'autant plus que (comme la plupart l'ont souligné) l'approche par itérateur que vous remplacez vous offre la fonctionnalité vous demandez alors que la déclaration for-each ne le fait pas. – delfuego

+0

Je voulais le remplacer pour l'élégance et la brièveté de la boucle pour chaque. Mais comme il ne peut pas couvrir les fonctionnalités existantes, j'abandonne l'idée. – Dan

+0

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

Répondre

21

for-each est juste du sucre syntaxique pour la version iterator et si vous vérifiez compilé bytecode, vous remarquerez que compilator changer réellement dans la version iterator.

Avec un formulaire pour chaque, vous ne pouvez pas vérifier si vous aurez plus d'éléments ou non. Restez simplement avec l'utilisation de l'itérateur explicite si vous avez besoin de cette fonctionnalité.

+4

..ou si vous avez besoin de la méthode Iterator # remove() (si elle est implémentée sur l'Iterator réel) –

+0

... ou si vous avez besoin de connaître l'index actuel d'un tableau, vous itérez sur –

+0

... cette dernière partie n'a de sens que quand c'est une liste ou un tableau; Sinon, vous devez créer et incrémenter un I séparé de toute façon, donc vous pouvez aussi bien utiliser la boucle foreach. –

0

Si vous voulez rester avec for-each peut-être quelque chose comme ceci:

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

Cela peut être assez cher pour les grandes listes. – Jorn

+1

Nous pouvons itérer (avec for-each) à travers n'importe quelle classe qui implémente l'interface Iterable, il ne doit pas être une liste et ofc n'a pas besoin de fournir une méthode indexOf –

1

Malheureusement, pour chaque idiome ne vous permet pas de vérifier si un élément est le premier ou le dernier dans la liste. C'est une limitation connue de la pour chaque boucle. Je vous suggère de continuer à utiliser l'itérateur.

Si vous pouvez également vérifier le premier élément au lieu du dernier, par exemple, si vous faites concaténation String, vous pouvez changer à quelque chose comme:

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

mais je préférerais en utilisant le iterator .

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

est le meilleur que je peux penser.

+3

Est-ce mieux que d'utiliser un Iterator explicite? la boucle for cependant? Je dirais que c'est plus bavard, moins évident de ce qui se passe et a plus de chance d'erreurs de logique que «if! Iter.hasNext()». –

+0

Non, je suis d'accord c'est une solution horrible. Je le retirerais mais je le laisserai ici pour avertir les autres. –

+2

Un autre problème ici est que vous supposez que vous avez une collection (c'est-à-dire que vous avez une méthode size()) et qu'il n'est pas cher de l'appeler. Vous pouvez avoir un objet Iterable général qui ne fournit pas de méthode size(). De cette façon, l'Iterator est la seule façon de faire. –

2

La boucle foreach (ou la boucle for améliorée) ne dispose pas des fonctions permettant de garder une trace de l'élément qui est en cours d'itération pour le moment. Il n'y a aucun moyen de savoir quel index d'un Collection est en cours de traitement, ou s'il y a plus d'éléments à traiter dans un . Cela dit, une solution de contournement qui fonctionnerait est de garder une référence à l'objet qui est itéré sur le moment dans la boucle foreach. En gardant une référence de ce sur quoi on travaillait à l'itération actuelle, on pourrait garder la référence une fois que la boucle foreach se termine, et ce qui reste dans la variable sera le dernier élément.

Cette solution de contournement fonctionnera uniquement si-et-seulement-si le dernier élément est le seul élément qui est nécessaire.

Par exemple:

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

Sortie:

c 
7

En plus de la réponse de Luno:

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

se traduit:

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

Comme d'autres l'ont dit - ce n'est pas possible. Rappelez-vous simplement que la construction foreach n'est pas l'alpha et l'oméga. Il a été introduit pour rendre la tâche très commune de en effectuant les mêmes opérations sur chaque élément d'une collection plus simple à désigner.

Dans votre cas, vous ne voulez pas faire exactement la même chose pour chaque élément - et donc une boucle foreach n'est pas le bon outil pour le travail. Essayer de le "pirater" pour le faire est stupide, il suffit d'utiliser un itérateur explicite dans une boucle classique.

0

Il y a deux cas possibles où vous voudriez faire ceci.

    Vous devez faire quelque chose après que le dernier élément a été atteint: dans ce cas, il vous suffit de mettre votre code en dehors de la boucle.

    
        for(Object item:theLinkedList){ 
    
        } 
        System.out.println("something special") 
    
    Vous devez modifier le dernier élément d'une manière ou utiliser les informations relatives au dernier élément. Dans ce cas, vous devez utiliser le ** LinkedList ** pour accéder au dernier élément

    for(Object item:theLinkedList){ 

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

oui vous pouvez, voici comment je le ferais si vous ne voulez pas utiliser la syntaxe explicite iterator:

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

Cela peut produire des faux positifs, si le dernier mot de la liste se produit plus d'une fois dans la liste, alors votre condition sera remplie pour chaque occurrence - et pas seulement la dernière occurrence. –

0

En plus de Bayer, vous devez le faire un peu différent car il n'y a pas de méthode getLast(). Mais au lieu de cela, vous pouvez utiliser ce objectList.size() - 1.

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

Il suffit d'enregistrer le nombre de répétitions en boucle, échantillon:

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++; 
    } 

Il est similaire à la boucle for(int i = 0; i < items.size(); i++);

items.size() est utilisé pour les listes et items.length pour les tableaux;