Pętla foreach
Spis treści
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 ...".
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<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>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<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>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>=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 >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<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 < 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<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<TypObiektu> 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<IEmploye> lista = new ArrayList<IEmploye>(); 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<Employe> lista = new ArrayList<Employe>(); </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.