Vodič za Java 8 forEach

1. Pregled

Predstavljen u Javi 8, za svakoga petlja pruža programerima novi, sažeti i zanimljiv način ponavljanja kolekcije.

U ovom ćemo članku vidjeti kako se koristi za svakoga s zbirkama, kakav je argument potreban i po čemu se ova petlja razlikuje od poboljšane za-petlju.

Ako trebate razjasniti neke koncepte Jave 8, imamo zbirku članaka koji vam mogu pomoći.

2. Osnove za svakoga

U Javi je Kolekcija sučelje ima Iterativ kao svoje super sučelje - a počevši od Jave 8, ovo sučelje ima novi API:

void forEach (Potrošačka akcija)

Jednostavno rečeno, Javadoc iz za svakoga statistika da je to "Izvodi zadanu radnju za svaki element Iterablea dok svi elementi nisu obrađeni ili radnja ne izuzme iznimku."

I tako, sa za svakoga, možemo prelaziti preko zbirke i izvoditi zadanu radnju na svakom elementu, kao i bilo koji drugi Iterator.

Na primjer, a za-petlju inačica ponavljanja i ispisa a Kolekcija od Žice:

za (Ime niza: imena) {System.out.println (ime); }

To možemo napisati koristeći za svakoga kao:

names.forEach (name -> {System.out.println (name);});

3. Korištenje za svakoga Metoda

Koristimo za svakoga iterirati preko zbirke i izvršiti određenu radnju na svakom elementu. Radnja koju treba izvesti sadržana je u klasi koja implementira Potrošač sučelje i prosljeđuje se na za svakoga kao argument.

The Potrošač sučelje je funkcionalno sučelje (sučelje s jednom apstraktnom metodom). Prihvaća ulaz i ne vraća rezultat.

Evo definicije:

@FunctionalInterface javno sučelje Potrošač {void accept (T t); }

Stoga, bilo koja implementacija, na primjer, potrošač koji jednostavno ispiše a Niz:

Potrošač printConsumer = new Consumer () {public void accept (naziv niza) {System.out.println (name); }; };

može se prenijeti na za svakoga kao argument:

imena.zaEach (printConsumer);

Ali to nije jedini način stvaranja radnje putem potrošača i korištenja za svakoga API.

Pogledajmo 3 najpopularnija načina na koje ćemo koristiti za svakoga metoda:

3.1. Anonimno Potrošač Provedba

Možemo instancirati provedbu Potrošač sučelje koristeći anonimnu klasu, a zatim ga primijenite kao argument na za svakoga metoda:

Potrošač printConsumer = new Consumer () {public void accept (naziv niza) {System.out.println (name); }}; imena.zaEach (printConsumer);

To dobro funkcionira, ali ako analiziramo u gornjem primjeru, vidjet ćemo da je stvarni dio koji se koristi kôd unutar prihvatiti() metoda.

Iako su Lambda izrazi sada norma i lakši način za to, ipak vrijedi znati kako implementirati Potrošač sučelje.

3.2. Lambda izraz

Glavna je prednost funkcionalnih sučelja Java 8 u tome što možemo koristiti Lambda izraze da bismo ih izradili i izbjegli upotrebu glomaznih implementacija anonimnih klasa.

Kao Potrošač Sučelje je funkcionalno sučelje, možemo ga izraziti na jeziku Lambda u obliku:

(argument) -> {// tijelo}

Stoga, naša printConsumer pojednostavljuje na:

ime -> System.out.println (ime)

I možemo ga proslijediti za svakoga kao:

names.forEach (name -> System.out.println (name));

Od uvođenja Lambda izraza u Javi 8, ovo je vjerojatno najčešći način korištenja za svakoga metoda.

Lambde imaju vrlo stvarnu krivulju učenja, pa ako započnete, ovo će opisati nekoliko dobrih praksi rada s novom jezičnom značajkom.

3.3. Referenca metoda

Možemo upotrijebiti referentnu sintaksu metode umjesto normalne Lambda sintakse gdje metoda već postoji za izvođenje operacije na klasi:

names.forEach (System.out :: println);

4. Rad sa za svakoga

4.1. Iteracija nad zbirkom

Bilo koji ponovljivi tip Zbirka - popis, skup, red itd. imaju istu sintaksu za upotrebu za svakoga.

Stoga, kao što smo već vidjeli, ponoviti elemente popisa:

Imena popisa = Arrays.asList ("Larry", "Steve", "James"); names.forEach (System.out :: println);

Slično za skup:

Postavi uniqueNames = novi HashSet (Arrays.asList ("Larry", "Steve", "James")); uniqueNames.forEach (System.out :: println);

Ili recimo za a Red što je također a Kolekcija:

Imena redaQueue = novi ArrayDeque (Arrays.asList ("Larry", "Steve", "James")); namesQueue.forEach (System.out :: println);

4.2. Iteriranje preko karte - Korištenje mapa za svakoga

Karte nisu Iterativ, ali, imaju pružiti vlastitu varijantu za svakoga koja prihvaća a BiConsumer.

A BiConsumer je uveden umjesto Potrošač u Iterable-u za svakoga tako da se radnja može izvršiti i na ključu i na vrijednosti a Karta istovremeno.

Stvorimo a Karta s unosima:

Imena mapa na mapi = nova HashMap (); namesMap.put (1, "Larry"); namesMap.put (2, "Steve"); namesMap.put (3, "James");

Dalje, ponovimo imenaKarta koristeći karte za svakoga:

namesMap.forEach ((ključ, vrijednost) -> System.out.println (ključ + "" + vrijednost));

Kao što ovdje možemo vidjeti, koristili smo BiConsumer:

(ključ, vrijednost) -> System.out.println (ključ + "" + vrijednost)

prelistavati unose Karta.

4.3. Iteriranje preko a Karta - iteriranjem entrySet

Također možemo ponoviti EntrySet od a Karta koristeći Iterable's za svakoga.

Od unosi a Karta su pohranjeni u a Postavi pozvao EntrySet, možemo ponoviti da pomoću a za svakoga:

namesMap.entrySet (). forEach (entry -> System.out.println (entry.getKey () + "" + entry.getValue ()));

5. Foreach vs For-Loop

S jednostavne točke gledišta, obje petlje pružaju istu funkcionalnost - provlače se kroz elemente u zbirci.

Glavna razlika između njih dvoje je ta što su različiti iteratori - poboljšani za-petlju je vanjski iterator dok je novi za svakoga metoda je interna.

5.1. Interni Iterator - za svakoga

Ova vrsta iteratora upravlja iteracijom u pozadini i ostavlja programeru da samo kodira ono što treba učiniti s elementima kolekcije.

Umjesto toga, iterator upravlja iteracijom i brine se da obrađuje elemente jedan po jedan.

Pogledajmo primjer internog iteratora:

names.forEach (name -> System.out.println (name));

U za svakoga gore opisane metode, možemo vidjeti da je navedeni argument lambda izraz. To znači da metodu treba samo znati što treba učiniti a sav posao ponavljanja bit će interno zbrinut.

5.2. Vanjski Iterator - za-petlju

Vanjski iteratori miješaju što i kako treba obaviti petlju.

Nabrajanja, Iteratore i poboljšana za-petlju su svi vanjski iteratori (sjetite se metoda iterator (),Sljedeći() ili hasNext () ? ). U svim tim iteratorima naš je posao odrediti način izvođenja iteracija.

Razmotrite ovu poznatu petlju:

za (Ime niza: imena) {System.out.println (ime); }

Iako se izričito ne pozivamo hasNext () ili Sljedeći() metode dok se iterira preko popisa, temeljni kod koji čini ovu iteraciju koristi ove metode. To implicira da je složenost ovih operacija skrivena od programera, ali još uvijek postoji.

Suprotno internom iteratoru u kojem zbirka sama ponavlja iteraciju, ovdje nam je potreban vanjski kôd koji uklanja svaki element iz zbirke.

6. Zaključak

U ovom smo članku pokazali da za svakoga petlja je prikladnija od normalne za-petlju.

Također smo vidjeli kako za svakoga metoda djeluje i koju vrstu implementacije može dobiti kao argument kako bi se izvršila radnja na svakom elementu u zbirci.

Napokon, svi isječci korišteni u ovom članku dostupni su u našem Github spremištu.