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 for
pętla bez użycia dla każdej składni?
java
foreach
syntactic-sugar
Jay R.
źródło
źródło
Odpowiedzi:
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
Iterable
interfejs .Ponadto, jeśli prawa strona
for (:)
idiomu jestarray
raczej obiektem niżIterable
obiektem, kod wewnętrzny używa licznika indeksu int i sprawdza warray.length
zamian. Zobacz specyfikację języka Java .źródło
import java.util.Iterator;
iimport java.lang.Iterable;
java.util.Iterator
nie implementuje,Iterable
więc nie możeszfor(String s : (Iterator<String>)foo)
. Rozumiem, dlaczego tak jest, ale to jest irytujące.Konstrukt dla każdego jest również poprawny dla tablic. na przykład
co jest zasadniczo równoważne z
Podsumowując:
[nsayer] Poniżej znajduje się dłuższa forma tego, co się dzieje:
[Denis Bueno]
źródło
foreach
Pętla , dodane w Javie 5 (zwane również „wzmocnione do pętli”), jest równoważna przy użyciujava.util.Iterator
cukru składniowej --it dla tej samej rzeczy. Dlatego podczas czytania każdego elementu, jeden po drugim i po kolei,foreach
należy zawsze wybierać a zamiast iteratora, ponieważ jest to wygodniejsze i bardziej zwięzłe.dla każdego
Iterator
Są sytuacje, w których musisz użyć
Iterator
bezpośrednio. Na przykład próba usunięcia elementu podczas korzystania zforeach
puszki (będzie?) Spowoduje utworzenie znakuConcurrentModificationException
.foreach
vsfor
.: Podstawowe różniceJedyną praktyczną różnicą między
for
iforeach
jest to, że w przypadku obiektów indeksowanych nie masz dostępu do indeksu. Przykład, gdyfor
wymagana jest podstawowa pętla:Chociaż możesz ręcznie utworzyć osobną zmienną indeksu za pomocą
foreach
,nie jest to zalecane, ponieważ zmienny zakres nie jest idealny, a podstawowa
for
pętla jest po prostu standardowym i oczekiwanym formatem dla tego przypadku użycia.foreach
vsfor
.: wydajnośćPodczas uzyskiwania dostępu do kolekcji, a
foreach
jest znacznie szybszy niżfor
dostę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
int
lubInteger
tablice. 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):Uruchomiłem to również dla
Integer
tablicy, 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
List
z nichIntegers
jednak iteratory są wyraźnym zwycięzcą. Wystarczy zmienić tablicę int w klasie testowej na:I wprowadź niezbędne zmiany w funkcji testowej (
int[]
doList<Integer>
,length
dosize()
itp.):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:
Zastosowania i składnia dla każdej pętli w Javie
Czy do iteracji powinienem używać iteratora lub forlaopa?
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 :
źródło
for(int value : int_array) {/* loop content */}
jest on najwolniejszy w twoim teście, ponieważ jest syntaktycznie równoważnyfor(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.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.)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:
Składnia foreach umożliwia zapisanie tego wspólnego wzorca w bardziej naturalny i mniej składniowo głośny sposób.
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.
źródło
Pętla for-each w Javie korzysta z mechanizmu iteratora. Jest to więc identyczne z następującymi:
źródło
W funkcjach Java 8 możesz użyć tego:
Wynik
źródło
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.
źródło
Jak zdefiniowano w JLS dla każdej pętli może mieć dwie formy:
Jeśli typ wyrażenia jest podtypem,
Iterable
wówczas tłumaczenie jest następujące:Jeśli wyrażenie musi koniecznie mieć typ tablicy,
T[]
to:Java 8 wprowadziła strumienie, które generalnie działają lepiej. Możemy ich używać jako:
źródło
Składnia pętli foreach to:
Przykład:
Wynik:
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
for
pętli.OSTRZEŻENIE: Musisz dopasować typ tablicy do drugiego obiektu.
Jeśli chcesz edytować elementy, użyj oryginalnej
for
pętli w następujący sposób:Teraz, gdy zrzucimy konsolę, otrzymamy:
źródło
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ę rozszerzaIterable<T>
.źródło
Pojęcie pętli foreach wspomnianej w Wikipedii zostało podkreślone poniżej:
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.
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.
źródło
W Javie 8 wprowadzono forEach. Korzystając z Listy, Mapy można zapętlać.
Zapętlić listę za pomocą dla każdego
lub
Zapętl mapę za pomocą każdego z nich
lub
źródło
źródło
Używając starszych wersji Java, w tym
Java 7
możesz użyćforeach
pętli w następujący sposób.Poniżej znajduje się najnowszy sposób korzystania z
foreach
pętliJava 8
(zapętlić listę z
forEach
wyrażeniem + lambda lub odwołanie do metody)Aby uzyskać więcej informacji, skorzystaj z tego linku.
https://www.mkyong.com/java8/java-8-foreach-examples/
źródło
Oto równoważne wyrażenie.
źródło
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.
źródło
removeIf
może być właściwym narzędziemAlternatywa dla forEach, aby uniknąć „za każdego”:
Wariant 1 (zwykły):
Wariant 2 (wykonanie równoległe (szybciej)):
źródło
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.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
for
pętla:Używając dla każdego:
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 ”.
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).
źródło
W wersjach wcześniejszych niż Java 8 musisz użyć:
Jednak dzięki wprowadzeniu strumieni w Javie 8 możesz zrobić to samo przy znacznie mniejszej składni. Na przykład,
someList
możesz:Więcej informacji o strumieniach można znaleźć tutaj .
źródło
The foreach loop, added in Java 5 (also called the "enhanced for loop"), is equivalent to using a java.util.Iterator
Wyglądałoby to mniej więcej tak. Bardzo kruche.
Jest dobry na writeup dla każdego w dokumentacji Sun .
źródło
Jak mówi wiele dobrych odpowiedzi, obiekt musi zaimplementować opcję,
Iterable interface
jeśli chce użyćfor-each
pętli.Podam prosty przykład i spróbuję wyjaśnić w inny sposób, jak
for-each
działa pętla.for-each
Przykład pętla:Następnie, jeśli użyjemy
javap
do dekompilacji tej klasy, otrzymamy przykładowy kod bajtowy:Jak widać z ostatniego wiersza próbki, kompilator automatycznie przekonwertuje użycie
for-each
słowa kluczowego na użycieIterator
w czasie kompilacji. To może wyjaśniać, dlaczego obiekt, który nie implementujeIterable interface
, rzuci an,Exception
gdy spróbuje użyćfor-each
pętli.źródło
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
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:
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.
Wynik:
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:
Deklaracja pętli stwierdza: zapętl myList List of String i zapisz bieżącą wartość List w zmiennej currentItem.
Wynik:
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:
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:
Źródło: Loops in Java - Ultimate Guide
źródło
źródło
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ę.
źródło
To wygląda na szalone, ale hej to działa
To działa. magia
źródło
Jak wiele innych odpowiedzi poprawnie stwierdza,
for
each
loop
jest to po prostu cukier składniowy na tym samym starym,for
loop
a 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ącoWięc usuńmy cukier syntaktyczny
Aby odpowiedzieć na to pytanie, utworzyłem plik i napisałem dwie wersje
for
each
, jedną zarray
drugą, a drugą zlist
. mójjava
plik wyglądał tak.Kiedy mam
compiled
ten plik z powyższym przełącznikiem, otrzymałem następujące dane wyjściowe.Możesz zobaczyć, że wraz z innym cukrem syntaktycznym (Autoboxing) dla każdej pętli zmieniono na proste pętle.
źródło
Iteruje po wszystkich obiektach w tabeli Przedmioty.
źródło