Wie funktioniert die Java-Schleife "für jede"?

1498

Erwägen:

List<String> someList = new ArrayList<String>();
// add "monkey", "donkey", "skeleton key" to someList
for (String item : someList) {
    System.out.println(item);
}

Wie würde die äquivalente forSchleife aussehen, ohne die für jede Syntax zu verwenden?

Jay R.
quelle
Laut
akhil_mittal

Antworten:

1175
for (Iterator<String> i = someIterable.iterator(); i.hasNext();) {
    String item = i.next();
    System.out.println(item);
}

Beachten Sie, dass Sie i.remove();das for ( : )Idiom nicht verwenden können , wenn Sie es in Ihrer Schleife verwenden oder auf irgendeine Weise auf den tatsächlichen Iterator zugreifen müssen , da der tatsächliche Iterator lediglich abgeleitet wird.

Wie von Denis Bueno festgestellt, funktioniert dieser Code für jedes Objekt, das die IterableSchnittstelle implementiert .

Wenn die rechte Seite des for (:)Idioms arrayeher ein IterableObjekt als ein Objekt ist, verwendet der interne Code einen int-Indexzähler und prüft array.lengthstattdessen. Siehe die Java-Sprachspezifikation .

nsayer
quelle
14
Ich habe gerade eine while-Schleife wie while aufgerufen (someList.hasMoreElements ()) {// etwas tun}} - bringt mich der Codierungsgnade nahe, die ich mir bei der Suche nach dieser Frage erhofft hatte.
James T Snell
6
Siehe auch docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html , die die foreach-Schleife (als sie eingeführt wurde) erklären
PhoneixS
1
für Android Studio Entwickler: import java.util.Iterator;undimport java.lang.Iterable;
dsdsdsdsd
Frustrierend, java.util.Iteratorimplementiert nicht, Iterableso dass Sie nicht können for(String s : (Iterator<String>)foo). Ich verstehe, warum das so ist, aber es ist irritierend.
Christopher Schultz
499

Das Konstrukt für jedes gilt auch für Arrays. z.B

String[] fruits = new String[] { "Orange", "Apple", "Pear", "Strawberry" };

for (String fruit : fruits) {
    // fruit is an element of the `fruits` array.
}

das ist im Wesentlichen gleichbedeutend mit

for (int i = 0; i < fruits.length; i++) {
    String fruit = fruits[i];
    // fruit is an element of the `fruits` array.
}

Gesamtzusammenfassung:
[nsayer] Das Folgende ist die längere Form des Geschehens:

for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
  String item = i.next();
  System.out.println(item);
}

Beachten Sie, dass, wenn Sie i.remove () verwenden müssen; In Ihrer Schleife oder wenn Sie auf irgendeine Weise auf den eigentlichen Iterator zugreifen, können Sie die Redewendung for (:) nicht verwenden, da der eigentliche Iterator lediglich abgeleitet wird.

[Denis Bueno]

Dies wird durch die Antwort von nsayer impliziert, aber es ist erwähnenswert, dass die OP-Syntax für (..) funktioniert, wenn "someList" etwas ist, das java.lang.Iterable implementiert - es muss keine Liste oder eine Sammlung von sein java.util. Daher können mit dieser Syntax auch Ihre eigenen Typen verwendet werden.

Mikezx6r
quelle
161

Die in Java 5 hinzugefügte foreachSchleife (auch als "Enhanced for Loop" bezeichnet) entspricht der Verwendung des syntaktischen Zuckers von --it für dasselbe. Daher sollte beim Lesen jedes Elements nacheinander und in der Reihenfolge a immer über einem Iterator ausgewählt werden, da dies bequemer und prägnanter ist.java.util.Iteratorforeach

für jedes

for(int i : intList) {
   System.out.println("An element in the list: " + i);
}

Iterator

Iterator<Integer> intItr = intList.iterator();
while(intItr.hasNext()) {
   System.out.println("An element in the list: " + intItr.next());
}

Es gibt Situationen, in denen Sie eine Iteratordirekt verwenden müssen. Wenn Sie beispielsweise versuchen, ein Element zu löschen, während Sie eine foreachDose verwenden (wird?), Führt dies zu a ConcurrentModificationException.

foreachvs for.: Grundlegende Unterschiede

Der einzige praktische Unterschied zwischen forund foreachbesteht darin, dass Sie bei indizierbaren Objekten keinen Zugriff auf den Index haben. Ein Beispiel, wenn die Basisschleife forbenötigt wird:

for(int i = 0; i < array.length; i++) {
   if(i < 5) {
      // Do something special
   }  else {
      // Do other stuff
   }
}

Obwohl Sie manuell eine separate Index-Int-Variable mit erstellen können foreach,

int idx = -1;
for(int i : intArray) {
   idx++;
   ...
}

Dies wird nicht empfohlen, da der variable Bereich nicht ideal ist und die Basisschleife foreinfach das Standard- und erwartete Format für diesen Anwendungsfall ist.

foreachvs for.: Leistung

Wenn Sammlungen zugreifen, eine foreachist wesentlich schneller als die Basis forArray - Zugriff-Schleife. Beim Zugriff auf Arrays ist der Zugriff über Indizes jedoch - zumindest bei primitiven und Wrapper-Arrays - erheblich schneller.

Timing des Unterschieds zwischen Iterator- und Indexzugriff für primitive Int-Arrays

Indizes sind beim Zugriff oder bei Arrays 23 bis 40 Prozent schneller als Iteratoren . Hier ist die Ausgabe der Testklasse am Ende dieses Beitrags, die die Zahlen in einem 100-Elemente-Primitive-Int-Array summiert (A ist Iterator, B ist Index):intInteger

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 358,597,622 nanoseconds
Test B: 269,167,681 nanoseconds
B faster by 89,429,941 nanoseconds (24.438799231635727% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 377,461,823 nanoseconds
Test B: 278,694,271 nanoseconds
B faster by 98,767,552 nanoseconds (25.666236154695838% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 288,953,495 nanoseconds
Test B: 207,050,523 nanoseconds
B faster by 81,902,972 nanoseconds (27.844689860906513% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,373,765 nanoseconds
Test B: 283,813,875 nanoseconds
B faster by 91,559,890 nanoseconds (23.891659337194227% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 375,790,818 nanoseconds
Test B: 220,770,915 nanoseconds
B faster by 155,019,903 nanoseconds (40.75164734599769% faster)

[C:\java_code\]java TimeIteratorVsIndexIntArray 1000000
Test A: 326,373,762 nanoseconds
Test B: 202,555,566 nanoseconds
B faster by 123,818,196 nanoseconds (37.437545972215744% faster)

Ich habe dies auch für ein IntegerArray ausgeführt, und Indizes sind immer noch der klare Gewinner, aber nur zwischen 18 und 25 Prozent schneller.

Bei Sammlungen sind Iteratoren schneller als Indizes

Für einen Listvon Integerssind jedoch Iteratoren der klare Gewinner. Ändern Sie einfach das int-Array in der Testklasse in:

List<Integer> intList = Arrays.asList(new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100});

Und nehmen Sie die notwendigen Änderungen an der Testfunktion vor ( int[]to List<Integer>, lengthto size(), etc.):

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,429,929,976 nanoseconds
Test B: 5,262,782,488 nanoseconds
A faster by 1,832,852,512 nanoseconds (34.326681820485675% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,907,391,427 nanoseconds
Test B: 3,957,718,459 nanoseconds
A faster by 1,050,327,032 nanoseconds (26.038700083921256% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,566,004,688 nanoseconds
Test B: 4,221,746,521 nanoseconds
A faster by 1,655,741,833 nanoseconds (38.71935684115413% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 2,770,945,276 nanoseconds
Test B: 3,829,077,158 nanoseconds
A faster by 1,058,131,882 nanoseconds (27.134122749113843% faster)

[C:\java_code\]java TimeIteratorVsIndexIntegerList 1000000
Test A: 3,467,474,055 nanoseconds
Test B: 5,183,149,104 nanoseconds
A faster by 1,715,675,049 nanoseconds (32.60101667104192% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,439,983,933 nanoseconds
Test B: 3,509,530,312 nanoseconds
A faster by 69,546,379 nanoseconds (1.4816434912159906% faster)

[C:\java_code\]java TimeIteratorVsIndexIntList 1000000
Test A: 3,451,101,466 nanoseconds
Test B: 5,057,979,210 nanoseconds
A faster by 1,606,877,744 nanoseconds (31.269164666060377% faster)

In einem Test sind sie fast gleichwertig, aber mit Sammlungen gewinnt der Iterator.

* Dieser Beitrag basiert auf zwei Antworten, die ich auf Stack Overflow geschrieben habe:

Weitere Informationen: Was ist effizienter, eine für jede Schleife oder ein Iterator?

Die vollständige Testklasse

Ich habe diese Klasse zum Vergleichen der Zeit erstellt, die benötigt wird, um zwei Dinge zu erledigen, nachdem ich diese Frage zu Stack Overflow gelesen habe :

import  java.text.NumberFormat;
import  java.util.Locale;

/**
   &lt;P&gt;{@code java TimeIteratorVsIndexIntArray 1000000}&lt;/P&gt;

   @see  &lt;CODE&gt;&lt;A HREF=&quot;/programming/180158/how-do-i-time-a-methods-execution-in-java&quot;&gt;/programming/180158/how-do-i-time-a-methods-execution-in-java&lt;/A&gt;&lt;/CODE&gt;
 **/
public class TimeIteratorVsIndexIntArray {

    public static final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);

    public static final void main(String[] tryCount_inParamIdx0) {
        int testCount;

        // Get try-count from a command-line parameter
        try {
           testCount = Integer.parseInt(tryCount_inParamIdx0[0]);
        }
        catch(ArrayIndexOutOfBoundsException | NumberFormatException x) {
           throw  new IllegalArgumentException("Missing or invalid command line parameter: The number of testCount for each test. " + x);
        }

        //Test proper...START
        int[] intArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100};

        long lStart = System.nanoTime();
        for(int i = 0; i < testCount; i++) {
           testIterator(intArray);
        }

        long lADuration = outputGetNanoDuration("A", lStart);

        lStart = System.nanoTime();
        for(int i = 0; i < testCount; i++) {
           testFor(intArray);
        }

        long lBDuration = outputGetNanoDuration("B", lStart);

        outputGetABTestNanoDifference(lADuration, lBDuration, "A", "B");
    }

    private static final void testIterator(int[] int_array) {
       int total = 0;
       for(int i = 0; i < int_array.length; i++) {
          total += int_array[i];
       }
    }

    private static final void testFor(int[] int_array) {
       int total = 0;
       for(int i : int_array) {
          total += i;
       }
    }
    //Test proper...END

    //Timer testing utilities...START
    public static final long outputGetNanoDuration(String s_testName, long l_nanoStart) {
        long lDuration = System.nanoTime() - l_nanoStart;
        System.out.println("Test " + s_testName + ": " + nf.format(lDuration) + " nanoseconds");
        return  lDuration;
    }

    public static final long outputGetABTestNanoDifference(long l_aDuration, long l_bDuration, String s_aTestName, String s_bTestName) {
        long lDiff = -1;
        double dPct = -1.0;
        String sFaster = null;
        if(l_aDuration > l_bDuration) {
            lDiff = l_aDuration - l_bDuration;
            dPct = 100.00 - (l_bDuration * 100.0 / l_aDuration + 0.5);
            sFaster = "B";
        }
        else {
            lDiff = l_bDuration - l_aDuration;
            dPct = 100.00 - (l_aDuration * 100.0 / l_bDuration + 0.5);
            sFaster = "A";
        }
        System.out.println(sFaster + " faster by " + nf.format(lDiff) + " nanoseconds (" + dPct + "% faster)");
        return  lDiff;
   }

   //Timer testing utilities...END

}
aliteralmind
quelle
4
Diese Antwort ist jetzt ein Blog-Beitrag und wurde aus zwei verwandten Antworten erstellt, die ich geschrieben habe: hier und hier . Es enthält auch eine allgemein nützliche Klasse zum Vergleichen der Geschwindigkeit zweier Funktionen (unten).
Aliteralmind
1
Nur ein kleiner Kommentar hier, Sie sollten nicht kategorisch angeben, dass die for (:) -Syntax für den Zugriff auf Sammlungen immer besser ist. Wenn Sie eine Array-Liste verwenden, ist die for (:) -Schleife etwa 2 x langsamer als die Verwendung von for (int i = 0, len = arrayList.size (); i <len; i ++). Ich denke, Sie haben das im Link [link] ( stackoverflow.com/questions/2113216/… ) trotzdem erwähnt, aber es ist wichtig hervorzuheben, dass ...
Leo
@ Leo Es ist ein guter Punkt. Eine ArrayList ist eine Sammlung, wird jedoch von einem Array unterstützt, weshalb das normale für besser ist.
Aliteralmind
Ich stelle mir vor, dass das for(int value : int_array) {/* loop content */}in Ihrem Test am langsamsten ist, weil es syntaktisch äquivalent zu for(int i = 0; i < int_array.length; i++) {int value = int_array[i]; /* loop content */}dem ist, was Ihr Test nicht vergleicht.
Daiscog
(Übrigens, ich sage nicht, dass Ihr Test ungültig ist, aber es könnte sich lohnen, die Gründe für den Unterschied zu erwähnen, damit die Leute wählen können, was für ihr bestimmtes Szenario richtig ist. Wenn sie int value = int_array[i];zu Beginn ihres Tests einen Test durchführen Schleife, dann könnten sie auch foreach verwenden. Es sei denn, sie benötigen aus irgendeinem Grund auch Zugriff auf den Index. Kurz gesagt, alles hängt vom Kontext ab.)
Daiscog
129

Hier ist eine Antwort, die keine Kenntnisse über Java-Iteratoren voraussetzt. Es ist weniger genau, aber es ist nützlich für die Bildung.

Während der Programmierung schreiben wir oft Code, der wie folgt aussieht:

char[] grades = ....
for(int i = 0; i < grades.length; i++) {   // for i goes from 0 to grades.length
    System.out.print(grades[i]);           // Print grades[i]
}

Die foreach-Syntax ermöglicht es, dieses allgemeine Muster natürlicher und weniger syntaktisch verrauscht zu schreiben.

for(char grade : grades) {   // foreach grade in grades
    System.out.print(grade); // print that grade
}

Darüber hinaus gilt diese Syntax für Objekte wie Listen oder Sets, die keine Array-Indizierung unterstützen, aber die Java Iterable-Schnittstelle implementieren.

MRocklin
quelle
40

Die for-each-Schleife in Java verwendet den zugrunde liegenden Iteratormechanismus. Es ist also identisch mit dem Folgenden:

Iterator<String> iterator = someList.iterator();

while (iterator.hasNext()) {
  String item = iterator.next();
  System.out.println(item);
}
Toluju
quelle
25

In Java 8-Funktionen können Sie Folgendes verwenden:

List<String> messages = Arrays.asList("First", "Second", "Third");

void forTest(){
    messages.forEach(System.out::println);
}

Ausgabe

First
Second
Third
Jrovalle
quelle
7
Diese zufällige Information beantwortet die Frage nicht einmal aus der Ferne
Tim
25

Dies wird durch die Antwort von nsayer impliziert, aber es ist erwähnenswert, dass die OP-Syntax für (..) funktioniert, wenn "someList" etwas ist , das java.lang.Iterable implementiert - es muss keine Liste oder eine Sammlung von sein java.util. Daher können mit dieser Syntax auch Ihre eigenen Typen verwendet werden.

EfForEffort
quelle
1
fd ist richtig - der interne Code, wenn die rechte Seite des for (:) -Idioms ein int und array.length verwendet, anstatt einen Iterator abzurufen. forums.sun.com/thread.jspa?messageID=2743233
nsayer
24

Wie in JLS für jede Schleife definiert, kann es zwei Formen geben:

  1. Wenn der Ausdruckstyp ein Subtyp von Iterableist, lautet die Übersetzung wie folgt:

    List<String> someList = new ArrayList<String>();
    someList.add("Apple");
    someList.add("Ball");
    for (String item : someList) {
        System.out.println(item);
    }
    
    // IS TRANSLATED TO:
    
    for(Iterator<String> stringIterator = someList.iterator(); stringIterator.hasNext(); ) {
        String item = stringIterator.next();
        System.out.println(item);
    }
  2. Wenn der Ausdruck notwendigerweise einen Array-Typ hat, T[]dann:

    String[] someArray = new String[2];
    someArray[0] = "Apple";
    someArray[1] = "Ball";
    
    for(String item2 : someArray) {
        System.out.println(item2);
    }
    
    // IS TRANSLATED TO:
    for (int i = 0; i < someArray.length; i++) {
        String item2 = someArray[i];
        System.out.println(item2);
    }

Java 8 hat Streams eingeführt, die im Allgemeinen eine bessere Leistung erzielen. Wir können sie verwenden als:

someList.stream().forEach(System.out::println);
Arrays.stream(someArray).forEach(System.out::println);
akhil_mittal
quelle
2
Die relevanteste und genaueste Antwort. Enchansed for hat in der Tat zwei Übersetzungen.
Zarial
23

Eine foreach-Schleifensyntax lautet:

for (type obj:array) {...}

Beispiel:

String[] s = {"Java", "Coffe", "Is", "Cool"};
for (String str:s /*s is the array*/) {
    System.out.println(str);
}

Ausgabe:

Java
Coffe
Is
Cool

WARNUNG: Sie können mit der foreach-Schleife auf Array-Elemente zugreifen, diese jedoch NICHT initialisieren. Verwenden Sie dazu die Originalschleife for.

WARNUNG: Sie müssen den Typ des Arrays mit dem anderen Objekt abgleichen.

for (double b:s) // Invalid-double is not String

Wenn Sie Elemente bearbeiten möchten, verwenden Sie die ursprüngliche forSchleife wie folgt:

for (int i = 0; i < s.length-1 /*-1 because of the 0 index */; i++) {
    if (i==1) //1 because once again I say the 0 index
        s[i]="2 is cool";
    else
        s[i] = "hello";
}

Wenn wir nun s auf die Konsole werfen, erhalten wir:

hello
2 is cool
hello
hello
PrivateName
quelle
21

Das Java-Schleifenkonstrukt "for-each" ermöglicht die Iteration über zwei Objekttypen:

  • T[] (Arrays jeglicher Art)
  • java.lang.Iterable<T>

Die Iterable<T>Schnittstelle hat nur eine Methode : Iterator<T> iterator(). Dies funktioniert bei Objekten vom Typ, Collection<T>da die Collection<T>Schnittstelle erweitert wird Iterable<T>.

Ryan Delucchi
quelle
16

Das in Wikipedia erwähnte Konzept einer foreach-Schleife wird nachfolgend hervorgehoben:

Im Gegensatz zu anderen for-Schleifenkonstrukten behalten foreach-Schleifen jedoch normalerweise keinen expliziten Zähler bei : Sie sagen im Wesentlichen "mache dies mit allem in dieser Menge" und nicht "mache dies x-mal". Dies vermeidet mögliche Fehler nacheinander und vereinfacht das Lesen von Code.

Das Konzept einer foreach-Schleife beschreibt also, dass die Schleife keinen expliziten Zähler verwendet, was bedeutet, dass keine Indizes zum Durchlaufen der Liste verwendet werden müssen, wodurch der Benutzer vor einem Fehler nach dem anderen geschützt wird. Um das allgemeine Konzept dieses Off-by-One-Fehlers zu beschreiben, nehmen wir ein Beispiel einer Schleife, die mithilfe von Indizes in einer Liste durchlaufen wird.

// In this loop it is assumed that the list starts with index 0
for(int i=0; i<list.length; i++){

}

Angenommen, die Liste beginnt mit Index 1, dann löst diese Schleife eine Ausnahme aus, da bei Index 0 kein Element gefunden wird und dieser Fehler als Fehler "Off-by-One" bezeichnet wird. Um diesen Fehler zu vermeiden, wird das Konzept einer foreach-Schleife verwendet. Es mag auch andere Vorteile geben, aber ich denke, dies ist das Hauptkonzept und der Vorteil der Verwendung einer foreach-Schleife.

Ein Bewusstsein
quelle
13

In Java 8 wurde forEach eingeführt. Mit dieser Liste können Karten geloopt werden.

Schleife eine Liste mit jedem

List<String> someList = new ArrayList<String>();
someList.add("A");
someList.add("B");
someList.add("C");

someList.forEach(listItem -> System.out.println(listItem))

oder

someList.forEach(listItem-> {
     System.out.println(listItem); 
});

Schleife eine Karte mit jedem

Map<String, String> mapList = new HashMap<>();
    mapList.put("Key1", "Value1");
    mapList.put("Key2", "Value2");
    mapList.put("Key3", "Value3");

mapList.forEach((key,value)->System.out.println("Key: " + key + " Value : " + value));

oder

mapList.forEach((key,value)->{
    System.out.println("Key : " + key + " Value : " + value);
});
vivekkurien
quelle
12
for (Iterator<String> itr = someList.iterator(); itr.hasNext(); ) {
   String item = itr.next();
   System.out.println(item);
}
Roger Lindsjö
quelle
11

Wenn Sie ältere Java-Versionen verwenden Java 7, können Sie die foreachSchleife wie folgt verwenden.

List<String> items = new ArrayList<>();
        items.add("A");
        items.add("B");
        items.add("C");
        items.add("D");
        items.add("E");

        for(String item : items){
            System.out.println(item);
        }

Im Folgenden finden Sie die neueste Methode zur Verwendung von foreachLoop-InJava 8

(Schleife einer Liste mit forEach+ Lambda-Ausdruck oder Methodenreferenz)

//lambda
    //Output : A,B,C,D,E
    items.forEach(item->System.out.println(item));


//method reference
    //Output : A,B,C,D,E
    items.forEach(System.out::println);

Weitere Informationen finden Sie unter diesem Link.

https://www.mkyong.com/java8/java-8-foreach-examples/

Dulith De Costa
quelle
10

Hier ist ein äquivalenter Ausdruck.

for(Iterator<String> sit = someList.iterator(); sit.hasNext(); ) {
    System.out.println(sit.next());
}
Strang
quelle
10

Beachten Sie auch, dass die Verwendung der "foreach" -Methode in der ursprünglichen Frage einige Einschränkungen aufweist, z. B., dass Elemente während der Iteration nicht aus der Liste entfernt werden können.

Die neue for-Schleife ist einfacher zu lesen und macht einen separaten Iterator überflüssig, kann jedoch nur in schreibgeschützten Iterationsdurchläufen verwendet werden.

billjamesdev
quelle
1
In diesen Fällen removeIfkönnte die Verwendung von das richtige Werkzeug sein
ncmathsadist
9

Eine Alternative zu forEach, um Ihr "für jeden" zu vermeiden:

List<String> someList = new ArrayList<String>();

Variante 1 (glatt):

someList.stream().forEach(listItem -> {
    System.out.println(listItem);
});

Variante 2 (parallele Ausführung (schneller)):

someList.parallelStream().forEach(listItem -> {
    System.out.println(listItem);
});
Alexander Drobyshevsky
quelle
2
Sollte erwähnen, dass es in Java 1.8 hinzugefügt wurde
TheLibrarian
Wir können nicht 100% sicher sein, dass der gleiche Thread verwendet wird. Ich verwende das for(Formular gerne, wenn ich sicherstellen möchte, dass der gleiche Thread verwendet wird. Ich verwende gerne das Stream-Formular, wenn ich die Multithread-Ausführung zulassen möchte.
Grim
8

Es verleiht Ihrem Code Schönheit, indem es alle grundlegenden Schleifen-Unordnung beseitigt. Es gibt Ihrem Code ein sauberes Aussehen, das unten begründet ist.

Normale forSchleife:

void cancelAll(Collection<TimerTask> list) {
    for (Iterator<TimerTask> i = list.iterator(); i.hasNext();)
         i.next().cancel();
}

Verwenden für jeden:

void cancelAll(Collection<TimerTask> list) {
    for (TimerTask t : list)
        t.cancel();
}

for-each ist ein Konstrukt über einer Sammlung, die Iterator implementiert . Denken Sie daran, dass Ihre Sammlung Iterator implementieren sollte . Andernfalls können Sie es nicht für jeden verwenden.

Die folgende Zeile lautet " für jede TimerTask t in Liste ".

for (TimerTask t : list)

Bei jedem Fall ist die Wahrscheinlichkeit von Fehlern geringer. Sie müssen sich nicht darum kümmern, den Iterator oder den Schleifenzähler zu initialisieren und zu beenden (wo Fehler auftreten können).

Manohar
quelle
8

Vor Java 8 müssen Sie Folgendes verwenden:

Iterator<String> iterator = someList.iterator();

while (iterator.hasNext()) {
    String item = iterator.next();
    System.out.println(item);
}

Mit der Einführung von Streams in Java 8 können Sie jedoch dasselbe mit viel weniger Syntax tun. Zum Beispiel können someListSie Folgendes tun:

someList.stream().forEach(System.out::println);

Weitere Informationen zu Streams finden Sie hier .

stackFan
quelle
The foreach loop, added in Java 5 (also called the "enhanced for loop"), is equivalent to using a java.util.Iterator
Alex78191
7

Es würde ungefähr so ​​aussehen. Sehr mürrisch.

for (Iterator<String> i = someList.iterator(); i.hasNext(); )
        System.out.println(i.next());

In der Sun-Dokumentation finden Sie jeweils eine gute Beschreibung .

Pete
quelle
6

Wie so viele gute Antworten sagten, muss ein Objekt das implementieren, Iterable interfacewenn es eine for-eachSchleife verwenden möchte .

Ich werde ein einfaches Beispiel posten und versuchen, auf andere Weise zu erklären, wie eine for-eachSchleife funktioniert.

Das for-eachSchleifenbeispiel:

public class ForEachTest {

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        list.add("111");
        list.add("222");

        for (String str : list) {
            System.out.println(str);
        }
    }
}

Wenn wir javapdann diese Klasse dekompilieren, erhalten wir dieses Bytecode-Beispiel:

public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #16                 // class java/util/ArrayList
         3: dup
         4: invokespecial #18                 // Method java/util/ArrayList."<init>":()V
         7: astore_1
         8: aload_1
         9: ldc           #19                 // String 111
        11: invokeinterface #21,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        16: pop
        17: aload_1
        18: ldc           #27                 // String 222
        20: invokeinterface #21,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        25: pop
        26: aload_1
        27: invokeinterface #29,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;

Wie wir in der letzten Zeile des Beispiels sehen können, konvertiert der Compiler die Verwendung des for-eachSchlüsselworts automatisch in die Verwendung eines Iteratorzur Kompilierungszeit. Dies kann erklären, warum ein Objekt, das das nicht implementiert Iterable interface, ein löst , Exceptionwenn es versucht, die for-eachSchleife zu verwenden.

L Joey
quelle
6

Das Java für jede Schleife (auch als erweiterte for-Schleife bezeichnet) ist eine vereinfachte Version einer for-Schleife. Der Vorteil ist, dass weniger Code geschrieben und weniger Variablen verwaltet werden müssen. Der Nachteil ist, dass Sie keine Kontrolle über den Schrittwert und keinen Zugriff auf den Schleifenindex innerhalb des Schleifenkörpers haben.

Sie werden am besten verwendet, wenn der Schrittwert ein einfaches Inkrement von 1 ist und Sie nur Zugriff auf das aktuelle Schleifenelement benötigen. Zum Beispiel, wenn Sie jedes Element in einem Array oder einer Sammlung durchlaufen müssen, ohne vor oder hinter das aktuelle Element zu schauen.

Es gibt keine Schleifeninitialisierung, keine boolesche Bedingung und der Schrittwert ist implizit und ein einfaches Inkrement. Aus diesem Grund werden sie für Schleifen als viel einfacher als normal angesehen.

Erweiterte for-Schleifen folgen dieser Ausführungsreihenfolge:

1) Schleifenkörper

2) Wiederholen Sie den Vorgang ab Schritt 1, bis das gesamte Array oder die gesamte Sammlung durchlaufen wurde

Beispiel - Integer Array

int [] intArray = {1, 3, 5, 7, 9};
for(int currentValue : intArray) {
  System.out.println(currentValue);
}

Die Variable currentValue enthält den aktuellen Wert, der im Array intArray durchlaufen wird. Beachten Sie, dass es keinen expliziten Schrittwert gibt - es ist immer ein Inkrement um 1.

Man kann sich vorstellen, dass der Doppelpunkt „in“ bedeutet. Die erweiterte for-Schleifendeklaration lautet also: Schleife über intArray und speichere den aktuellen Array-Int-Wert in der Variablen currentValue.

Ausgabe:

1
3
5
7
9

Beispiel - String Array

Wir können die for-each-Schleife verwenden, um über ein Array von Zeichenfolgen zu iterieren. Die Schleifendeklaration lautet: Schleife über das Array myStrings String und speichere den aktuellen String-Wert in der Variablen currentString.

String [] myStrings  = {
  "alpha",
  "beta",
  "gamma",
  "delta"
};

for(String currentString : myStrings) {
  System.out.println(currentString);
}

Ausgabe:

alpha
beta
gamma
delta

Beispiel - Liste

Die erweiterte for-Schleife kann auch verwendet werden, um eine java.util.List wie folgt zu durchlaufen:

List<String> myList = new ArrayList<String>();
myList.add("alpha");
myList.add("beta");
myList.add("gamma");
myList.add("delta");

for(String currentItem : myList) {
  System.out.println(currentItem);
}

Die Schleifendeklaration lautet: Schleife über myList Liste der Zeichenfolgen und speichere den aktuellen Listenwert in der Variablen currentItem.

Ausgabe:

alpha
beta
gamma
delta

Beispiel - Set

Die erweiterte for-Schleife kann auch verwendet werden, um eine java.util.Set wie folgt zu durchlaufen:

Set<String> mySet = new HashSet<String>();
mySet.add("alpha");
mySet.add("alpha");
mySet.add("beta");
mySet.add("gamma");
mySet.add("gamma");
mySet.add("delta");

for(String currentItem : mySet) {
  System.out.println(currentItem);
}

Die Schleifendeklaration lautet: Schleife über mySet Set of Strings und speichere den aktuellen Set-Wert in der currentItem-Variablen. Beachten Sie, dass doppelte String-Werte nicht gespeichert werden, da dies ein Set ist.

Ausgabe:

alpha
delta
beta
gamma

Quelle: Schleifen in Java - Ultimate Guide

Gomisha
quelle
4
public static Boolean Add_Tag(int totalsize)
{ List<String> fullst = new ArrayList<String>();
            for(int k=0;k<totalsize;k++)
            {
              fullst.addAll();
            }
}
Santhosh Rajkumar
quelle
3

Das Java für jedes Idiom kann nur auf Arrays oder Objekte vom Typ * Iterable angewendet werden . Diese Redewendung ist implizit, da sie wirklich von einem Iterator unterstützt wird. Der Iterator wird vom Programmierer programmiert und verwendet häufig einen ganzzahligen Index oder einen Knoten (abhängig von der Datenstruktur), um seine Position zu verfolgen. Auf dem Papier ist es langsamer als eine reguläre for-Schleife, zumindest für "lineare" Strukturen wie Arrays und Listen, aber es bietet eine größere Abstraktion.

TheArchon
quelle
-1: Dies ist (im Allgemeinen) viel weniger lesbar: Selbst Ihr eigenes Beispiel (das erste) ist falsch, da das erste Element im Array weggelassen wird.
Ondrej Skopek
2

Das sieht verrückt aus, aber hey, es funktioniert

List<String> someList = new ArrayList<>(); //has content
someList.forEach(System.out::println);

Das funktioniert. Magie

Rei Brown
quelle
1
Dies erfordert Java 1.8 +
BARNI
2
beantwortet die Frage nicht einmal aus der Ferne
Tim
2

Wie viele andere Antworten richtig angeben, for each loopist der Zucker nur syntaktisch über dieselbe alte for loopund der Compiler übersetzt ihn in dieselbe alte for-Schleife.

javac (open jdk) hat einen Schalter -XD-printflat, der eine Java-Datei generiert, in der der gesamte syntaktische Zucker entfernt ist. Der vollständige Befehl sieht folgendermaßen aus

javac -XD-printflat -d src/ MyFile.java

//-d is used to specify the directory for output java file

Entfernen wir also den syntaktischen Zucker

Um diese Frage zu beantworten, habe ich eine Datei erstellt und zwei Versionen von geschrieben for each, eine mit arrayund eine mit a list. Meine javaDatei sah so aus.

import java.util.*;
public class Temp{

    private static void forEachArray(){
        int[] arr = new int[]{1,2,3,4,5};
        for(int i: arr){
            System.out.print(i);
        }
    }

    private static void forEachList(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        for(Integer i: list){
            System.out.print(i);
        }
    }
}

Wenn ich compileddiese Datei mit dem obigen Schalter habe, habe ich die folgende Ausgabe erhalten.

import java.util.*;

public class Temp {

    public Temp() {
        super();
    }

    private static void forEachArray() {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        for (/*synthetic*/ int[] arr$ = arr, len$ = arr$.length, i$ = 0; i$ < len$; ++i$) {
            int i = arr$[i$];
            {
                System.out.print(i);
            }
        }
    }

    private static void forEachList() {
        List list = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5)});
        for (/*synthetic*/ Iterator i$ = list.iterator(); i$.hasNext(); ) {
            Integer i = (Integer)i$.next();
            {
                System.out.print(i);
            }
        }
    }
}

Sie können sehen, dass zusammen mit dem anderen syntaktischen Zucker (Autoboxing) für jede Schleife in einfache Schleifen geändert wurde.

mächtige WOZ
quelle
-2
List<Item> Items = obj.getItems();
for(Item item:Items)
             {
                System.out.println(item); 
             }

Iteriert über alle Objekte in der Elementtabelle.

Shubhranshu
quelle
1
Benutzer hat nicht nach Syntax gefragt
Pradipgarala