Gids voor de Java 8 forEach

1. Overzicht

Geïntroduceerd in Java 8, de voor elk loop biedt programmeurs een nieuwe, beknopte en interessante manier om een ​​verzameling te herhalen.

In dit artikel zullen we zien hoe u voor elk met verzamelingen, wat voor soort argument er nodig is en hoe deze lus verschilt van de verbeterde for loop.

Als u enkele concepten van Java 8 moet opfrissen, hebben we een verzameling artikelen die u kunnen helpen.

2. Basisprincipes van voor elk

In Java is het Verzameling interface heeft Herhaalbaar als zijn superinterface - en te beginnen met Java 8 heeft deze interface een nieuwe API:

void forEach (actie van de consument)

Simpel gezegd, de Javadoc van voor elk stats dat het "Voert de gegeven actie uit voor elk element van de iterabele totdat alle elementen zijn verwerkt of de actie een uitzondering genereert."

En dus met voor elkkunnen we een verzameling herhalen en een bepaalde actie op elk element uitvoeren, net als elk ander Iterator.

Bijvoorbeeld een for loop versie van itereren en afdrukken van een Verzameling van Snaren:

voor (String naam: namen) {System.out.println (naam); }

We kunnen dit schrijven met voor elk net zo:

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

3. Gebruik de voor elk Methode

We gebruiken voor elk om een ​​verzameling te herhalen en een bepaalde actie op elk element uit te voeren. De uit te voeren actie is opgenomen in een klasse die de Klant interface en wordt doorgegeven aan voor elk als argument.

De Klant interface is een functionele interface (een interface met een enkele abstracte methode). Het accepteert invoer en geeft geen resultaat.

Hier is de definitie:

@FunctionalInterface openbare interface Consument {ongeldig accepteren (T t); }

Daarom is elke implementatie, bijvoorbeeld een consument die gewoon een Draad:

Consumer printConsumer = new Consumer () {public void accept (String name) {System.out.println (name); }; };

kan worden doorgegeven aan voor elk als argument:

names.forEach (printConsumer);

Maar dat is niet de enige manier om via een consument een actie te creëren en te gebruiken voor elk API.

Laten we eens kijken naar de 3 meest populaire manieren waarop we de voor elk methode:

3.1. Anoniem Klant Implementatie

We kunnen een implementatie van het Klant interface met behulp van een anonieme klasse en deze vervolgens als argument toepassen op de voor elk methode:

Consumer printConsumer = new Consumer () {public void accept (String name) {System.out.println (name); }}; names.forEach (printConsumer);

Dit werkt goed, maar als we het bovenstaande voorbeeld analyseren, zullen we zien dat het daadwerkelijke deel dat van nut is de code in de aanvaarden() methode.

Hoewel Lambda-expressies nu de norm en eenvoudigere manier zijn om dit te doen, is het toch de moeite waard om te weten hoe u het Klant koppel.

3.2. Een Lambda-uitdrukking

Het grote voordeel van functionele Java 8-interfaces is dat we Lambda-expressies kunnen gebruiken om ze te instantiëren en het gebruik van omvangrijke anonieme klasse-implementaties kunnen vermijden.

Net zo Klant Interface is een functionele interface, we kunnen het in Lambda uitdrukken in de vorm van:

(argument) -> {// body}

Daarom onze printConsumer vereenvoudigt tot:

name -> System.out.println (naam)

En we kunnen het doorgeven aan voor elk net zo:

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

Sinds de introductie van Lambda-expressies in Java 8 is dit waarschijnlijk de meest gebruikelijke manier om de voor elk methode.

Lambda's hebben een heel reële leercurve, dus als je begint, gaat dit artikel over een aantal goede praktijken voor het werken met de nieuwe taalfunctie.

3.3. Een methodereferentie

We kunnen de syntaxis van de methode-referentie gebruiken in plaats van de normale Lambda-syntaxis als er al een methode bestaat om een ​​bewerking op de klasse uit te voeren:

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

4. Werken met voor elk

4.1. Een verzameling herhalen

Elk iterabel type Collectie - lijst, set, wachtrij enz. hebben dezelfde syntaxis voor gebruik voor elk.

Daarom, zoals we al hebben gezien, om elementen van een lijst te herhalen:

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

Evenzo voor een set:

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

Of laten we zeggen voor een Wachtrij wat ook een Verzameling:

WachtrijnamenQueue = nieuwe ArrayDeque (Arrays.asList ("Larry", "Steve", "James")); namesQueue.forEach (System.out :: println);

4.2. Itereren over een kaart - Kaarten gebruiken voor elk

Kaarten zijn dat niet Herhaalbaar, maar ze doen bieden hun eigen variant van voor elk dat accepteert een BiConsumer.

EEN BiConsumer werd geïntroduceerd in plaats van Klant in Iterable's voor elk zodat een actie kan worden uitgevoerd op zowel de sleutel als de waarde van een Kaart gelijktijdig.

Laten we een Kaart ingangen hebben:

Map namesMap = nieuwe HashMap (); namesMap.put (1, "Larry"); namesMap.put (2, "Steve"); namesMap.put (3, "James");

Laten we het vervolgens herhalen namesMap met behulp van kaarten voor elk:

namesMap.forEach ((sleutel, waarde) -> System.out.println (sleutel + "" + waarde));

Zoals we hier kunnen zien, hebben we een BiConsumer:

(sleutel, waarde) -> System.out.println (sleutel + "" + waarde)

om de vermeldingen van de Kaart.

4.3. Itereren over een Kaart - door Iterating entrySet

We kunnen ook de EntrySet van een Kaart met behulp van Iterable's voor elk.

Sinds de vermeldingen van een Kaart worden opgeslagen in een Set gebeld EntrySet, we kunnen dat herhalen met behulp van een voor elk:

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

5. Foreach versus For-Loop

Vanuit een eenvoudig oogpunt bieden beide loops dezelfde functionaliteit: elementen in een verzameling doorlopen.

Het belangrijkste verschil tussen de twee is dat het verschillende iteratoren zijn - de verbeterde for loop is een externe iterator terwijl de nieuwe voor elk methode is een interne.

5.1. Interne iterator - voor elk

Dit type iterator beheert de iteratie op de achtergrond en laat de programmeur alleen coderen wat er met de elementen van de verzameling moet worden gedaan.

De iterator beheert in plaats daarvan de iteratie en zorgt ervoor dat de elementen één voor één worden verwerkt.

Laten we een voorbeeld bekijken van een interne iterator:

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

In de voor elk methode hierboven, kunnen we zien dat het opgegeven argument een lambda-uitdrukking is. Dit betekent dat de methode alleen hoeft te weten wat er moet gebeuren en al het iteratiewerk wordt intern afgehandeld.

5.2. Externe iterator - for loop

Externe iterators mengen het wat en de hoe de lus moet worden gedaan.

Opsommingen, Iteratoren en verbeterd for loop zijn allemaal externe iteratoren (onthoud de methodes iterator (),De volgende() of hasNext () ? ). In al deze iterators is het onze taak om te specificeren hoe iteraties moeten worden uitgevoerd.

Beschouw deze bekende lus:

voor (String naam: namen) {System.out.println (naam); }

Hoewel we er niet expliciet een beroep op doen hasNext () of De volgende() methodes tijdens het itereren over de lijst, gebruikt de onderliggende code die deze iteratie laat werken deze methodes. Dit houdt in dat de complexiteit van deze bewerkingen verborgen is voor de programmeur, maar nog steeds bestaat.

In tegenstelling tot een interne iterator waarin de collectie de iteratie zelf doet, hebben we hier externe code nodig die elk element uit de collectie haalt.

6. Conclusie

In dit artikel hebben we laten zien dat de voor elk lus is handiger dan normaal for loop.

We hebben ook gezien hoe de voor elk methode werkt en wat voor soort implementatie als argument kan ontvangen om een ​​actie uit te voeren op elk element in de verzameling.

Ten slotte zijn alle fragmenten die in dit artikel worden gebruikt, beschikbaar in onze Github-repository.


$config[zx-auto] not found$config[zx-overlay] not found