Jak działa pętla Java dla każdej pętli?

1498

Rozważać:

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

Jak wyglądałaby równoważna forpętla bez użycia dla każdej składni?

Jay R.
źródło
Zgodnie z JLS ma dwie formy: stackoverflow.com/a/33232565/1216775
akhil_mittal

Odpowiedzi:

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

Zauważ, że jeśli potrzebujesz użyć i.remove();w swojej pętli lub uzyskać dostęp do faktycznego iteratora w jakiś sposób, nie możesz użyć for ( : )idiomu, ponieważ rzeczywisty iterator jest jedynie wywnioskowany.

Jak zauważył Denis Bueno, ten kod działa dla każdego obiektu, który implementuje Iterableinterfejs .

Ponadto, jeśli prawa strona for (:)idiomu jest arrayraczej obiektem niż Iterableobiektem, kod wewnętrzny używa licznika indeksu int i sprawdza w array.lengthzamian. Zobacz specyfikację języka Java .

nsayer
źródło
14
Znalazłem właśnie wywoływanie pętli while, jak while (someList.hasMoreElements ()) {// zrób coś}} - zbliża mnie do łaski kodowania, którą chciałem znaleźć, kiedy szukałem tego pytania.
James T Snell
6
Zobacz także docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html, które wyjaśniają pętlę foreach (kiedy została wprowadzona)
PhoneixS
1
dla programistów Androida: import java.util.Iterator;iimport java.lang.Iterable;
dsdsdsdsd
Frustrująco, java.util.Iteratornie implementuje, Iterablewięc nie możesz for(String s : (Iterator<String>)foo). Rozumiem, dlaczego tak jest, ale to jest irytujące.
Christopher Schultz
499

Konstrukt dla każdego jest również poprawny dla tablic. na przykład

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

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

co jest zasadniczo równoważne z

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

Podsumowując:
[nsayer] Poniżej znajduje się dłuższa forma tego, co się dzieje:

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

Zauważ, że jeśli potrzebujesz użyć i.remove (); w pętli lub w jakikolwiek sposób uzyskać dostęp do rzeczywistego iteratora, nie można użyć idiomu for (:), ponieważ rzeczywisty Iterator jest jedynie wywnioskowany.

[Denis Bueno]

Sugeruje to odpowiedź nsayera, ale warto zauważyć, że składnia OP dla (..) będzie działać, gdy „someList” to cokolwiek, co implementuje java.lang.Iterable - nie musi to być lista ani część kolekcji z java.util. Dlatego w tej składni można używać nawet własnych typów.

Mikezx6r
źródło
161

foreachPętla , dodane w Javie 5 (zwane również „wzmocnione do pętli”), jest równoważna przy użyciu java.util.Iteratorcukru składniowej --it dla tej samej rzeczy. Dlatego podczas czytania każdego elementu, jeden po drugim i po kolei, foreachnależy zawsze wybierać a zamiast iteratora, ponieważ jest to wygodniejsze i bardziej zwięzłe.

dla każdego

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

Są sytuacje, w których musisz użyć Iteratorbezpośrednio. Na przykład próba usunięcia elementu podczas korzystania z foreachpuszki (będzie?) Spowoduje utworzenie znaku ConcurrentModificationException.

foreachvs for.: Podstawowe różnice

Jedyną praktyczną różnicą między fori foreachjest to, że w przypadku obiektów indeksowanych nie masz dostępu do indeksu. Przykład, gdy forwymagana jest podstawowa pętla:

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

Chociaż możesz ręcznie utworzyć osobną zmienną indeksu za pomocą foreach,

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

nie jest to zalecane, ponieważ zmienny zakres nie jest idealny, a podstawowa forpętla jest po prostu standardowym i oczekiwanym formatem dla tego przypadku użycia.

foreachvs for.: wydajność

Podczas uzyskiwania dostępu do kolekcji, a foreachjest znacznie szybszy niż fordostęp do tablicy podstawowej pętli. Jednak podczas uzyskiwania dostępu do tablic - przynajmniej w przypadku tablic pierwotnych i tablic opakowujących - dostęp za pośrednictwem indeksów jest znacznie szybszy.

Zmierz różnicę czasu między iteratorem a dostępem do indeksu dla prymitywnych tablic int

Indeksy są 23- 40 procent szybciej niż iteratorów przy dostępie intlub Integertablice. Oto dane wyjściowe z klasy testowej na dole tego postu, która sumuje liczby w 100-elementowej macierzy pierwotnej-int (A to iterator, B to indeks):

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

Uruchomiłem to również dla Integertablicy, a indeksy nadal są wyraźnym zwycięzcą, ale tylko między 18 a 25 procent szybciej.

W przypadku kolekcji iteratory są szybsze niż indeksy

Dla jednego Listz nich Integersjednak iteratory są wyraźnym zwycięzcą. Wystarczy zmienić tablicę int w klasie testowej na:

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

I wprowadź niezbędne zmiany w funkcji testowej ( int[]do List<Integer>, lengthdo size()itp.):

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

W jednym teście są prawie równoważne, ale w kolekcjach wygrywa iterator.

* Ten post jest oparty na dwóch odpowiedziach, które napisałem na temat przepełnienia stosu:

Więcej informacji: która z nich jest bardziej wydajna, dla każdej pętli lub iteratora?

Pełna klasa testowa

Po przeczytaniu tego pytania na temat przepełnienia stosu utworzyłem tę klasę porównującą czas potrzebny na wykonanie dwóch dowolnych rzeczy :

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
źródło
4
Ta odpowiedź jest teraz postem na blogu i została utworzona z dwóch powiązanych odpowiedzi, które napisałem: tu i tutaj . Zawiera także ogólnie użyteczną klasę do porównywania prędkości dwóch funkcji (na dole).
aliteralmind
1
Tylko jeden drobny komentarz tutaj, nie powinieneś kategorycznie stwierdzać, że dla (:) składnia jest zawsze lepsza do uzyskiwania dostępu do kolekcji; jeśli używasz listy tablic, pętla for (:) będzie około 2 x wolniejsza niż przy użyciu for (int i = 0, len = arrayList.size (); i <len; i ++). Myślę, że wspomniałeś o tym w linku [ stackoverflow.com/questions/2113216/... ], ale ważne jest, aby podkreślić, że ...
Leo
@Leo To dobra uwaga. ArrayList to kolekcja, ale jest ona wspierana przez tablicę, dlatego normalna dla jest dla niej lepsza.
aliteralmind
Wyobrażam sobie, że for(int value : int_array) {/* loop content */}jest on najwolniejszy w twoim teście, ponieważ jest syntaktycznie równoważny for(int i = 0; i < int_array.length; i++) {int value = int_array[i]; /* loop content */}, co nie jest tym, co porównuje twój test.
daiscog,
(swoją drogą, nie twierdzę, że test jest nieważny, ale warto zwrócić uwagę na przyczyny tej różnicy, aby ludzie mogli wybrać to, co jest odpowiednie dla ich konkretnego scenariusza. Jeśli robią int value = int_array[i];na początku pętli, mogliby równie dobrze użyć foreach. Chyba, że ​​z jakiegoś powodu również potrzebują dostępu do indeksu. Krótko mówiąc, wszystko zależy od kontekstu.)
daiscog
129

Oto odpowiedź, która nie zakłada znajomości iteratorów Java. Jest mniej precyzyjny, ale przydaje się w edukacji.

Podczas programowania często piszemy kod, który wygląda następująco:

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]
}

Składnia foreach umożliwia zapisanie tego wspólnego wzorca w bardziej naturalny i mniej składniowo głośny sposób.

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

Dodatkowo ta składnia jest poprawna dla obiektów takich jak Listy lub Zestawy, które nie obsługują indeksowania tablic, ale które implementują interfejs Java Iterable.

MRocklin
źródło
40

Pętla for-each w Javie korzysta z mechanizmu iteratora. Jest to więc identyczne z następującymi:

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

while (iterator.hasNext()) {
  String item = iterator.next();
  System.out.println(item);
}
toluju
źródło
25

W funkcjach Java 8 możesz użyć tego:

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

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

Wynik

First
Second
Third
Jrovalle
źródło
7
ta losowa informacja nawet nie odpowiada zdalnie na pytanie
Tim
25

Sugeruje to odpowiedź nsayera, ale warto zauważyć, że składnia OP dla (..) będzie działać, gdy „someList” to cokolwiek , co implementuje java.lang.Iterable - nie musi to być lista ani zbiór z java.util. Dlatego w tej składni można używać nawet własnych typów.

EfForEffort
źródło
1
fd ma rację - wewnętrzny kod, gdy po prawej stronie id (for) idiom używa int i array.length zamiast pobierania iteratora. forums.sun.com/thread.jspa?messageID=2743233
nsayer
24

Jak zdefiniowano w JLS dla każdej pętli może mieć dwie formy:

  1. Jeśli typ wyrażenia jest podtypem, Iterablewówczas tłumaczenie jest następujące:

    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. Jeśli wyrażenie musi koniecznie mieć typ tablicy, T[]to:

    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 wprowadziła strumienie, które generalnie działają lepiej. Możemy ich używać jako:

someList.stream().forEach(System.out::println);
Arrays.stream(someArray).forEach(System.out::println);
akhil_mittal
źródło
2
Najbardziej trafna i dokładna odpowiedź. Enchansed ma rzeczywiście dwa tłumaczenia.
Zarial
23

Składnia pętli foreach to:

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

Przykład:

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

Wynik:

Java
Coffe
Is
Cool

OSTRZEŻENIE: Możesz uzyskać dostęp do elementów tablicy za pomocą pętli foreach, ale NIE możesz ich zainicjować. Użyj do tego oryginalnej forpętli.

OSTRZEŻENIE: Musisz dopasować typ tablicy do drugiego obiektu.

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

Jeśli chcesz edytować elementy, użyj oryginalnej forpętli w następujący sposób:

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

Teraz, gdy zrzucimy konsolę, otrzymamy:

hello
2 is cool
hello
hello
PrivateName
źródło
21

Konstrukcja pętli Java „for-each” pozwoli na iterację dwóch typów obiektów:

  • T[] (tablice dowolnego typu)
  • java.lang.Iterable<T>

Iterable<T>Interfejs ma tylko jedną metodę: Iterator<T> iterator(). Działa to na obiektach typu, Collection<T>ponieważ Collection<T>interfejs się rozszerza Iterable<T>.

Ryan Delucchi
źródło
16

Pojęcie pętli foreach wspomnianej w Wikipedii zostało podkreślone poniżej:

Jednak w przeciwieństwie do innych konstrukcji pętli, pętle foreach zwykle nie mają wyraźnego licznika : w zasadzie mówią „rób to wszystko w tym zestawie”, a nie „rób to x razy”. Pozwala to uniknąć potencjalnych błędów off-by-one i ułatwia odczytanie kodu.

Tak więc koncepcja pętli foreach opisuje, że pętla nie używa żadnego jawnego licznika, co oznacza, że ​​nie ma potrzeby używania indeksów do przechodzenia na liście, dzięki czemu ratuje użytkownika przed błędem „jeden po drugim”. Aby opisać ogólną koncepcję tego błędu off-by-one, weźmy przykład pętli przechodzącej przez listę za pomocą indeksów.

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

}

Przypuśćmy jednak, że jeśli lista zaczyna się od indeksu 1, wówczas ta pętla wygeneruje wyjątek, ponieważ nie znajdzie elementu o indeksie 0, a błąd ten nazywa się błędem off-by-one. Aby uniknąć tego błędu jeden po drugim, zastosowano koncepcję pętli foreach. Mogą być też inne zalety, ale myślę, że to jest główna koncepcja i zaleta korzystania z pętli foreach.

oneConsciousness
źródło
13

W Javie 8 wprowadzono forEach. Korzystając z Listy, Mapy można zapętlać.

Zapętlić listę za pomocą dla każdego

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

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

lub

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

Zapętl mapę za pomocą każdego z nich

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

lub

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

Używając starszych wersji Java, w tym Java 7możesz użyć foreachpętli w następujący sposób.

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

Poniżej znajduje się najnowszy sposób korzystania z foreachpętliJava 8

(zapętlić listę z forEachwyrażeniem + lambda lub odwołanie do metody)

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

Aby uzyskać więcej informacji, skorzystaj z tego linku.

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

Dulith De Costa
źródło
10

Oto równoważne wyrażenie.

for(Iterator<String> sit = someList.iterator(); sit.hasNext(); ) {
    System.out.println(sit.next());
}
Motek
źródło
10

Należy również pamiętać, że użycie metody „foreach” w pierwotnym pytaniu ma pewne ograniczenia, takie jak niemożność usunięcia elementów z listy podczas iteracji.

Nowa pętla for jest łatwiejsza do odczytania i eliminuje potrzebę oddzielnego iteratora, ale jest naprawdę użyteczna tylko w przejściach iteracyjnych tylko do odczytu.

billjamesdev
źródło
1
W takich przypadkach użycie removeIfmoże być właściwym narzędziem
ncmathsadist
9

Alternatywa dla forEach, aby uniknąć „za każdego”:

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

Wariant 1 (zwykły):

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

Wariant 2 (wykonanie równoległe (szybciej)):

someList.parallelStream().forEach(listItem -> {
    System.out.println(listItem);
});
Alexander Drobyshevsky
źródło
2
Należy wspomnieć, że został dodany w Javie 1.8
TheLibrarian
Nie możemy być w 100% pewni, że użyto tego samego wątku. Lubię używać for(formularza, jeśli chcę się upewnić, że ten sam wątek jest używany. Lubię używać formularza strumieniowego, jeśli chcę zezwalać na wykonywanie wielowątkowe.
Ponury
8

To dodaje urody Twojemu kodowi poprzez usunięcie całego podstawowego bałaganu zapętlonego. Daje czysty wygląd twojego kodu, uzasadnionego poniżej.

Normalna forpętla:

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

Używając dla każdego:

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

for-each to konstrukcja nad kolekcją, która implementuje Iterator . Pamiętaj, że twoja kolekcja powinna implementować Iterator ; w przeciwnym razie nie będzie można go używać z każdym z nich.

Następujący wiersz jest czytany jako „ dla każdego TimerTask t na liście ”.

for (TimerTask t : list)

Jest mniej szans na błędy w przypadku for-each. Nie musisz się martwić inicjowaniem iteratora lub inicjowaniem licznika pętli i kończeniem go (tam, gdzie jest miejsce na błędy).

Manohar
źródło
8

W wersjach wcześniejszych niż Java 8 musisz użyć:

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

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

Jednak dzięki wprowadzeniu strumieni w Javie 8 możesz zrobić to samo przy znacznie mniejszej składni. Na przykład, someListmożesz:

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

Więcej informacji o strumieniach można znaleźć tutaj .

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

Wyglądałoby to mniej więcej tak. Bardzo kruche.

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

Jest dobry na writeup dla każdego w dokumentacji Sun .

Pete
źródło
6

Jak mówi wiele dobrych odpowiedzi, obiekt musi zaimplementować opcję, Iterable interfacejeśli chce użyć for-eachpętli.

Podam prosty przykład i spróbuję wyjaśnić w inny sposób, jak for-eachdziała pętla.

for-eachPrzykład pętla:

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

Następnie, jeśli użyjemy javapdo dekompilacji tej klasy, otrzymamy przykładowy kod bajtowy:

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;

Jak widać z ostatniego wiersza próbki, kompilator automatycznie przekonwertuje użycie for-eachsłowa kluczowego na użycie Iteratorw czasie kompilacji. To może wyjaśniać, dlaczego obiekt, który nie implementuje Iterable interface, rzuci an, Exceptiongdy spróbuje użyć for-eachpętli.

P Joey
źródło
6

Java dla każdej pętli (alias zwiększonej pętli) jest uproszczoną wersją pętli. Zaletą jest to, że jest mniej kodu do napisania i mniej zmiennych do zarządzania. Minusem jest to, że nie masz kontroli nad wartością kroku i nie masz dostępu do indeksu pętli wewnątrz ciała pętli.

Są najlepiej stosowane, gdy wartość kroku jest prostą inkrementacją 1 i gdy potrzebujesz tylko dostępu do bieżącego elementu pętli. Na przykład, jeśli chcesz zapętlić każdy element w tablicy lub kolekcji bez zaglądania przed lub za bieżącym elementem.

Nie ma inicjalizacji pętli, warunku logicznego, a wartość kroku jest niejawna i jest prostym przyrostem. Dlatego są one uważane za znacznie prostsze niż zwykłe dla pętli.

Ulepszone dla pętli mają następującą kolejność wykonywania:

1) korpus pętli

2) powtarzaj od kroku 1 do momentu przejścia całej tablicy lub kolekcji

Przykład - tablica liczb całkowitych

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

Zmienna currentValue przechowuje bieżącą wartość zapętloną w tablicy intArray. Zauważ, że nie ma wyraźnej wartości kroku - zawsze jest to przyrost o 1.

Okrężnica może oznaczać „w”. Ulepszone stany deklaracji pętli: zapętlają intArray i przechowują bieżącą wartość int tablicy w zmiennej currentValue.

Wynik:

1
3
5
7
9

Przykład - tablica ciągów

Możemy użyć pętli for-each do iteracji po tablicy ciągów. Deklaracja pętli stwierdza: zapętlać tablicę myStrings String i przechowywać bieżącą wartość String w zmiennej currentString.

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

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

Wynik:

alpha
beta
gamma
delta

Przykład - lista

Ulepszoną pętlę for można także wykorzystać do iteracji po pliku java.util.List w następujący sposób:

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

Deklaracja pętli stwierdza: zapętl myList List of String i zapisz bieżącą wartość List w zmiennej currentItem.

Wynik:

alpha
beta
gamma
delta

Przykład - Ustaw

Ulepszoną pętlę for można także wykorzystać do iteracji po pliku java.util.Set w następujący sposób:

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

Deklaracja pętli stwierdza: zapętla mySet Set of Strings i przechowuje bieżącą wartość Set w zmiennej currentItem. Zauważ, że ponieważ jest to zestaw, zduplikowane wartości ciągu nie są przechowywane.

Wynik:

alpha
delta
beta
gamma

Źródło: Loops in Java - Ultimate Guide

Gomisha
źródło
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
źródło
3

Idiom Java dla każdego można zastosować tylko do tablic lub obiektów typu * Iterable . Ten idiom jest domyślny, ponieważ jest naprawdę poparty przez Iterator. Iterator jest programowany przez programistę i często używa indeksu liczb całkowitych lub węzła (w zależności od struktury danych) do śledzenia jego pozycji. Na papierze jest wolniejszy niż zwykła pętla for, przynajmniej dla struktur „liniowych”, takich jak tablice i listy, ale zapewnia większą abstrakcję.

TheArchon
źródło
-1: jest to mniej czytelne (ogólnie): nawet twój własny przykład (pierwszy) jest błędny, ponieważ pomija pierwszy element w tablicy.
Ondrej Skopek
2

To wygląda na szalone, ale hej to działa

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

To działa. magia

Rei Brown
źródło
1
Wymaga to Java 1.8 +
BARNI
2
nawet nie zdalnie odpowiada na pytanie
Tim
2

Jak wiele innych odpowiedzi poprawnie stwierdza, for each loopjest to po prostu cukier składniowy na tym samym starym, for loopa kompilator tłumaczy go na ten sam stary dla pętli for.

javac (open jdk) ma przełącznik -XD-printflat, który generuje plik java z usuniętym całym cukrem składniowym. kompletne polecenie wygląda następująco

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

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

Więc usuńmy cukier syntaktyczny

Aby odpowiedzieć na to pytanie, utworzyłem plik i napisałem dwie wersje for each, jedną z arraydrugą, a drugą z list. mój javaplik wyglądał tak.

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

Kiedy mam compiledten plik z powyższym przełącznikiem, otrzymałem następujące dane wyjściowe.

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

Możesz zobaczyć, że wraz z innym cukrem syntaktycznym (Autoboxing) dla każdej pętli zmieniono na proste pętle.

mightyWOZ
źródło
-2
List<Item> Items = obj.getItems();
for(Item item:Items)
             {
                System.out.println(item); 
             }

Iteruje po wszystkich obiektach w tabeli Przedmioty.

shubhranshu
źródło
1
Użytkownik nie poprosił o składnię
pradipgarala