Pętla foreach


Pętla for each to konstrukcja, która pozwala na sekwencyjne przeglądanie różnych zbiorów danych. Mogą nimi być tablice, a także dynamiczne struktury jak na przykład listy.

Teoria

Schematyczna konstrukcja pętli for each wygląda następująco:

for(Typ_Obiektu nazwa_obiektu : nazwa_tablicy){ ... }
lub
for(Typ_Obiektu nazwa_obiektu : nazwa_kolekcji){ ... }

Powyższy zapis można traktować dosłownie tak jak nazywa się ten typ pętli "dla każdego elementu z tablicy ...", lub "dla każdego(kolejnego) elementu kolekcji ...".

Kurs Java

Praktyczny przykład

Utwórzmy 10 elementową tablicę liczb typu całkowitoliczbowego i wypełnijmy ją wartościami od 1 do 10. Następnie przy użyciu pętli for each wyświetlmy kolejne liczby i zobaczmy jakie to proste.

public class Test {
    public static void main(String args[]) {
        int[] tablica = new int[10];
        //wypełnienie tablicy
        for (int i = 0; i < 10; i++) {
            tablica[i] = i + 1;
        }

        //wyświetlenie przy użyciu pętli for each
        for (int x : tablica) {
            System.out.println(x);
        }
    }
}

Jak widać pętla for each znacznie upraszcza i sprawia, że kod dzięki temu często może być dużo czytelniejszy. Warto jej używać szczególnie w przypadku tablic z długimi nazwami z oczywistych względów.

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.

Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.

tomek

Przede wszystkim chciałbym pogratulować świetnego kursu, przejrzałem kilka i ten zdecydowanie do mnie przemawia, jest czytelny, wszystko fajnie wytłumaczone, a tego mi brakowało ;) A teraz a propos kodu: for(int i=0; i&lt;10; i++) tablica[i] = i+1; Czemu tutaj nie ma zamykających i otwierających klamerek? Wiem, że bez nich działa, bo sprawdziłem ale w temacie pętle pokazywałeś pętle for z użyciem klamerki

Slawek

Zacytuję siebie z tematu o pętlach: <blockquote>Podobnie jak przy instrukcji warunkowej if można pominąć nawiasy klamrowe w wypadku, gdy w ciele pętli znajduje się tylko jedna metoda.</blockquote> Jeśli pominiesz klamry, to w ciele pętli wykona się tylko instrukcja występująca bezpośrednio po niej. Jeśli użyjesz klamer to możesz tam umieścić na przykład wywołanie kilku metod, wyświetlenie tekstu i jeszcze inne instrukcje sterujące.

Ktoś

Tak na chłopski rozum, klamry mówią "wykonuj w pętli wszystko co jest między klamerkami" a jak ich nie ma to wykona tylko to co znajduje się pod (zaraz po) definicji pętli

DDO

Brak klamer to podstawa nawet w Pascalu nie było znacznikow dla 1 lini :-)

Marcin Kunert

Zasady Clean Code radzą zawsze używać klamerek. Kod jest wtedy zdecydowanie bardziej czytelny.

DDO

Nie w przypadku 1 liniowych if(parametr) //zadanie else if (parametr2) //zadanie [...] else(parametr3) //zadanie

mabiki

Ciało pętli to zawsze następna instrukcja. Instrukcje można łączyć w bloki za pośrednictwem nawiasów klamorowych przez co traktowane są przez pętlę jako jedna instrukcja.

Pajączek

Jak else, to już bez (parametr) !!!!

Krzysiek

A jak wypenić tabele aby wpisły się w nią liczby w odwrotnej numeracji, nie od 1 do 10 tylko od 10 do 1? Jest to możliwe?

Marcin

<blockquote> <a href="#comment-1536" rel="nofollow"> <strong><em>Krzysiek:</em></strong> </a> A jak wypenić tabele aby wpisły się w nią liczby w odwrotnej numeracji, nie od 1 do 10 tylko od 10 do 1? Jest to możliwe? </blockquote> public class Test { public static void main(String args[]){ int[] tablica = new int[10]; //wypełnienie tablicy for(int i=10; i&gt;10; i--) tablica[i] = i-1; //wyświetlenie przy użyciu pętli for each for(int x : tablica) System.out.println(x); } } Jeśli dobrze myślę, to własnie tak.

Raqs

To nie jest raczej dobrze. W tym wypadku wypełnia tablicę od końca i wstawia liczby też od końca. Można wypełniać jeszcze jedną zmienną, która startuje z długością tablicy(10) i przy każdym kroku zmniejsza się o 1. --- public class Test { public static void main(String args[]){ int[] tablica = new int[10]; //wypełnienie tablicy int j = tablica.length; for(int i=0; i&lt;10; i++){ tablica[i] = j; j--;} //wyświetlenie przy użyciu pętli for each for(int x : tablica) System.out.println(x); } }

Krzysiek

Teraz działa;) Wygląda na to że bez instrukcji nazwa_tablicy.length to nic z tego by nie wyszło. Ja kombinowałem wcześniej podobnie jak kolega Marcin czyli pętelkowanie w drugą stronę (w dół), ale jak widać nie wszystko jest tu analogicznie logiczne;)))

Krzysiek

Sorry to jeszcze ja. Instrukcja nazwa_tablicy.lenght to tylko odpowiednik długości tablicy czyli liczby jej elementów. Tak wiec mozna intowi przypisać odrazu ilość tych elementów liczbą np. 10, 20, 30 itd. Potrzebujemy tylko dodatkowej zmiennej a nie tej instrukcja chociaż warto o niej wiedzieć. Ale ja głupi jestem. Dzięki

anonim

to chyba oczywiste, że ta pętla nie działa ponieważ warunek i&gt;10 nie jest już spełniony w momencie jej wykonywania. <code> int[] tablica = new int[10]; int k=10; for(int i=tablica.length-1; i&gt;=0; i--){ tablica[tablica.length-k] = i+1; k--; } for(int x : tablica) System.out.print(x + " "); </code>

DDO

Ale to i tak nie dokonca dobrze, bo co jak poda tablice &gt;10 ?? Wtedy funkcja nie wypelni wszystkich komurek, zamiast 10 w petli trzeba zastosowac zmienna rowna ilosci pol tablicy powinno byc public class Test { public static void main(String args[]){ int[] tablica = new int[10]; //wypełnienie tablicy int j,a = tablica.length; for(int i=0; i&lt;a; i++){ tablica[i] = j; j–;} //wyświetlenie przy użyciu pętli for each for(int x : tablica) System.out.println(x); } }

V0ldek

<code>for(int x : tablica)</code> Nie rozumiem co to znaczy. Czemu nie ma średników i co znaczy dwukropek? I dlaczego nie ma modyfikatora licznika?

Witek

Witam Pętla ta automatycznie przechodzi przez wszystkie elementy tablicy lub też kolekcji od początku do końca. for( typ zmienna – interacyjna : tablica) zmienna interacyjna czyli w twoim przypadku „x” będzie miał dostęp do kolejnych elementów tablicy(kolekcji). Np.: <code> int tab[] = {1,2,3,4,5,6,7,8,9,10}; int suma = 0; for(int i = 0; i &lt; 10; i++) suma += tab[i]; </code> To samo tylko z wykorzystaniem rozszerzonej pętli for –each <code> int tab[] = {1,2,3,4,5,6,7,8,9,10}; int suma = 0; for(int x : tab) suma += x; </code> Jak widać jest dużo prościej i nie musisz się obawiać o przekroczenie rozmiaru tablicy

Kelzaer

<cite> for(int x : tablica) Nie rozumiem co to znaczy. Czemu nie ma średników i co znaczy dwukropek? I dlaczego nie ma modyfikatora licznika? </cite> Przeczytaj jeszcze raz wstęp do tego rozdziału. Szczególnie tę część: <cite> Schematyczna konstrukcja pętli for each wygląda następująco: <code> for(Typ_Obiektu nazwa_obiektu : nazwa_tablicy){ ... } </code> </cite> W opisanym zadaniu mamy: "Typ_Obiektu nazwa_obiektu" ="int x" następnie dwukropek ":" i na koniec "nazwa_tablicy" = "tablica" Mogło zmylić Cię to, że pętla for each zaczyna się tak jako zwykły for - <code> for(... </code> Jednak po zawartości między nawiasami można wywnioskować, że jest to właśnie for each :)

Dawid

Czy ta pętla jest konieczna tylko względem prostszego pisania kodów czy jest ważna do nauczenia się? Bo ja tej for each nie kumam.

Slawek

To tylko ficzer, spokojnie możesz używać zwykłej for, albo while. Po pewnym czasie wróć sobie do niej to wszystko będzie jasne.

gandy

Czy w javie istnieje możliwość iteracji elementów tablicy od innej wartości początkowej czy też zawsze do pierwszego elementu tablicy musimy się odwoływać jako do elementu zerowego?

Slawek

Wykorzystując zwykłą pętlę for, a nie for each możesz iterować od którego elementu Ci się podoba.

gandy

Nie o to mi chodziło. Tylko o to czy możemy w jakiś sposób inaczej indeksować elementy tablicy o nazwie np. tab tzn nie element 0,1,2,3,4,5 ( dla sześciu elementów) tylko np element 4,5,6,7,8,9(dla takiej samej ilości) , a później odwoływać się do poszczególnych elementów przez tab[4],tab[5],tab[6],tab[7],tab[8],tab[9]. Czy też iteracja pierwszego elementu jako zerowego jest niemożliwa do obejścia?

Slawek

Nie da się tego obejść, musiałbyś stworzyć własną klasę i opakować tablicę - ale nie ma to większego sensu.

jestęsobą

Bardzo dobry kurs. Doceniam to, że chcesz pomóc, lecz staraj się pisać językiem prostszym(takim, żeby rozumieli go tacy jak ja- czyli ci, którzy po raz pierwszy się z Javą stykają. Pozdrawiam :)

Fryta

Witam, troche już programuje (od 2 technikum do teraz, czyli 7 lat, niestety jako samouk) ale w JAVA siedze dopiero drugi dzień. Odnośnie wypełnienia tablicy od 10 do 1 to można zrealizować następująco: for (int i=0 ; i&lt;10 ; i++) tablica[i] = 10-i; Wiem, że odpowiedź jest troche późna (po roku) ale może się komuś przyda. Jeśli chodzi o kurs to miewam pewne problemy przy polimorfizmie, klasach abstrakcyjnych i interfejsie. Reszta kursu jest świetna. Sławku, czy ty piszesz aplikacje na androida i czy jesteś może na Google Play? Chciałbym poznać kilka twoich projektów - podejrzewam, że bardzo rozbudowane i dopracowane skoro Jave masz w małym paluszku. Jakbyś mógł pochwalić się swoim dorobkiem byłbym wdzięczny:D

Max

<blockquote> <a href="#comment-3618" rel="nofollow"> <strong><em>jestęsobą:</em></strong> </a> Bardzo dobry kurs. Doceniam to, że chcesz pomóc, lecz staraj się pisać językiem prostszym(takim, żeby rozumieli go tacy jak ja- czyli ci, którzy po raz pierwszy się z Javą stykają. Pozdrawiam </blockquote> Eee, kurs jest baaardzo przystępnie napisany, zaczynałem bez żadnego pojęcia od pierwszej lekcji. Najlepszym sposobem nauki dla mnie jest przeczytanie lekcji, zrobienie zadań i przeczytanie i analiza wszystkich komentarzy, szczególnie tych zawierających kody programu. Skończyłem właśnie kurs podstawowy i będę zaczynał programowanie obiektowe. Na razie jeszcze nie wiem czym się zajmują programiści w dużych korpo, zarabiający 200k rocznie, bo przypuszczam że nie wypełniają tablic żeby wybuchła bomba albo kalkulator BMI . Ale nie zawracam sobie tym głowy. Podobnie nie zawracałem sobie głowy tym, że nie mam logicznego obrazowego pojęcia klasy, przyjmuję to póki co jako warunek konieczny do dalszego pisania programu. Na marginesie fajna zabawa z tym programowaniem, taki język matematyczny, symboliczny ;)

Dcortez

Jak powinno się definiować tym w pętli foreach gdy nasza kolekcja jest definiowana interfejsem, np. List workers = new ArrayList; Klasa zawierająca ową kolekcje implementuje Iterable i ma napisany iterator. W tym wypadku rozumiem że jak przykładowy x zostanie stworzony właśnie ten iterator, a nie instancja klasy?

Sławek Ludwiczak

To, czy referencja kolekcji będzie interfejsem, czy konkretną klasą nie ma znaczenia (przy czym należy pamiętać, że wywoływana jest metoda na rzecz obiektu, nie typu referencji i że nie mamy wtedy dostępu do wszystkich metod klasy bez rzutowania). Pętla foreach wygląda dokładnie tak samo niezależnie od sposobu utworzenia kolekcji. Nie do końca też rozumiem Twoje pytanie, więc jeśli możesz to odpisz czy o to chodziło: Zmienna x nie jest iteratorem, jest to zmienna konkretnego typu, która stanowi kopię referencji do danego obiektu udostępnianego przez iterator. Do x w kolejnych iteracjach przypisywana jest wartość z wywołania meotdy next() iteratora danej kolekcji. Inaczej pętlę for each można by zapisać jako: <pre name='code' class='java'> for(Iterator&lt;TypObiektu&gt; i = collection.iterator(); i.hasNext(); ) { TypObiektu item = i.next(); Działania na referencji item będącej kopią oryginalnej referencji } </pre> Bardzo ważne jest to, że w pętli for each nie działamy na oryginalnych referencjach, a na ich kopii. Do kolejnych elementów kolekcji nie przypiszemy więc za jej pomocą nowych obiektów i jest to często spotykany błąd. For each'a bezpieczniej jest używać tylko do odczytu.

Dcortez

Dzięki za odpowiedź. Widze że niestety ucieło mi troche poprzedniego komentarza albo nie uważnie go wpisałem. Mianowicie byłem ciekawy czy gdy użyję generycznej listy inicjowanej nie tyle konkretną klasą a interfejsem, przypuśćmy IEmployee, to moge potem iterować po tej kolekcji w ten sposób: for ( IEmployee x: workers) { do sth.. } Zastanawiałem się czy będzie to składniowo poprawne, ale jeśli dobrze rozumiem sprawi to że wywoła się odpowiedni iterator a z x w kolejnych przejsciach beda podstawiane odpowiednie elementy z kolekcji?

Sławek Ludwiczak

Jeśli chodzi Ci o coś takiego: <pre name='code' class='java'> List&lt;IEmploye&gt; lista = new ArrayList&lt;IEmploye&gt;(); for(IEmploye e: lista) sth... </pre> to oczywiście, że można tak robić. Jeśli określisz typ listy jako konkretny typ, a nie interfejs, np: <pre name='code' class='java'> List&lt;Employe&gt; lista = new ArrayList&lt;Employe&gt;(); </pre> to możesz po niej iterować w identyczny sposób jak powyżej, zakładając, że Employe jest klasą implementującą interfejs IEmploye.

SAK

Dzięki bardzo! Właśnie coś podobnego kombinowałem, ale nie wiedziałem jak to dokładnie zapisać.. :)

PanKitke

Napotkałem następujący problem. Chcę, żeby ilość pól w tabeli była uzależniona od danych wprowadzonych przez użytkownika. Zapis: int ilePol; int[] tablica = new int[ilePol]; grzecznie się kompiluje, jednak przy probie wypełnienia tablicy przy użyciu pętli pojawia się błąd java.lang.ArrayIndexOutOfBoundsException: 10. PS Czy w Javie jest (pewnie jest ;-)) odpowiednik var_dump z PHP?

PanKitke

OK... odpowiedź znajduje się w następnej lekcji... :-)

Marcin Kunert

Podejrzewam, że zarezerwowałeś miejsce na 10 liczb. Pamiętaj jednak o tym, że numerowane jest od 0. tablica ma elementy od tablica[0] do tablica[9]. Co do var_dump - nie spotkałem się, ale debugowanie w Javie rozwiązuje ten problem. Ustawiasz sobie breakpointa w momencie gdzie chcesz sprawdzić obiekt, zaznaczasz go i naciskasz Ctrl+Shift+I (Inspect chyba)

k2marko

Może ktoś wytłumaczyć dlaczego w tym przypadku w metodzie main kwadratowe nawiasy są dopiero po "args" a nie, tak jak zwykle, po "String"? Czy ma to jakiekolwiek znaczenie? Pytam bo nigdy wcześniej się z tym nie spotkałem. Nigdy to znaczy od początku tego kursu :)

Sławek Ludwiczak

Oba sposoby zapisu są poprawne i są sobie równoznaczne. Możesz dać kwadratowe nawiasy przy typie, albo przy zmiennej.