Principes
De principes van het werken met de Stream API zijn gebaseerd op de belangrijkste concepten van functioneel programmeren en luie evaluatie. Hieronder volgt een overzicht van de belangrijkste principes van de Stream API.
Luie evaluatie
Een van de kernprincipes van de Stream API is luie evaluatie.
Dit houdt in dat intermediaire operaties zoals filter() of map() niet direct worden uitgevoerd. Ze vormen slechts een keten van acties die pas worden uitgevoerd wanneer een terminale operatie, zoals collect() of forEach(), wordt aangeroepen.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }
Deze code maakt een stream van een lijst met strings, filtert de elementen om alleen die te behouden die beginnen met de letter A, en telt hoeveel aan deze voorwaarde voldoen. Het resultaat (1) wordt afgedrukt omdat alleen Alice aan de voorwaarde voldoet.
Functionele programmeerstijl
De Stream API maakt gebruik van lambda-expressies en functionele interfaces voor gegevensverwerking. In plaats van de imperatieve aanpak met lussen, beschrijf je wat er met de gegevens moet gebeuren:
Main.java
1234567891011121314package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }
Deze code maakt een stream van een lijst met fruitsoorten, zet de strings om naar hoofdletters met behulp van map(), en slaat de eerste drie elementen over met skip(). Het resultaat wordt verzameld in een nieuwe lijst en afgedrukt, beginnend vanaf het vierde element.
Onveranderlijkheid van gegevens
De Stream API wijzigt de oorspronkelijke gegevens niet. Alle bewerkingen creëren een nieuwe stream of geven een resultaat terug zonder de collectie of array te wijzigen. Dit verhoogt de gegevensveiligheid en voorkomt onverwachte neveneffecten.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }
De Stream API filtert de lijst namen om een nieuwe stream, updateNames, te creëren die alleen elementen bevat die beginnen met de letter A. De oorspronkelijke lijst namen blijft echter ongewijzigd, omdat de Stream API de gegevens niet direct wijzigt, wat gegevensveiligheid waarborgt en neveneffecten voorkomt.
Streams zijn slechts één keer te gebruiken
Een stream kan slechts één keer worden gebruikt. Nadat een terminale bewerking is uitgevoerd, is de stream niet langer beschikbaar voor verdere verwerking.
Main.java
123456789101112package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }
Hier wordt een stream gemaakt van een lijst met strings en wordt elk element naar de console geprint. Nadat de stream voor de eerste keer is gebruikt, kan deze niet opnieuw worden gebruikt, wat een fout veroorzaakt als u probeert opnieuw forEach() aan te roepen.
Parallelle verwerking
De Stream API ondersteunt parallelle streams, waardoor snellere gegevensverwerking op multi-core systemen mogelijk is. Dit wordt uitgebreider besproken hier
Main.java
1234567891011package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }
Deze code maakt een parallelle stream van een lijst met getallen en print elk element naar de console. Door gebruik te maken van parallelStream() wordt parallelle verwerking van de lijstelementen mogelijk, wat de uitvoering kan versnellen bij het werken met grote datasets.
Codezuiverheid en Leesbaarheid
Het gebruik van de Stream API maakt de code meer declaratief. In plaats van te beschrijven hoe een taak moet worden uitgevoerd (zoals met lussen), wordt beschreven wat precies moet gebeuren. Dit verhoogt de leesbaarheid en vereenvoudigt het onderhoud van de code.
Voorbeeld met een lus:
List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
Voorbeeld met Stream API:
List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);
In het eerste lusvoorbeeld beschrijven we expliciet hoe we door de lijst moeten itereren en de elementen moeten afdrukken, terwijl we in het tweede voorbeeld met de Stream API eenvoudig aangeven wat er moet gebeuren: itereren door de elementen en deze afdrukken. Dit maakt de code meer declaratief en leesbaar.
Bedankt voor je feedback!
Vraag AI
Vraag AI
Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.
Awesome!
Completion rate improved to 2.33
Principes
Veeg om het menu te tonen
De principes van het werken met de Stream API zijn gebaseerd op de belangrijkste concepten van functioneel programmeren en luie evaluatie. Hieronder volgt een overzicht van de belangrijkste principes van de Stream API.
Luie evaluatie
Een van de kernprincipes van de Stream API is luie evaluatie.
Dit houdt in dat intermediaire operaties zoals filter() of map() niet direct worden uitgevoerd. Ze vormen slechts een keten van acties die pas worden uitgevoerd wanneer een terminale operatie, zoals collect() of forEach(), wordt aangeroepen.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }
Deze code maakt een stream van een lijst met strings, filtert de elementen om alleen die te behouden die beginnen met de letter A, en telt hoeveel aan deze voorwaarde voldoen. Het resultaat (1) wordt afgedrukt omdat alleen Alice aan de voorwaarde voldoet.
Functionele programmeerstijl
De Stream API maakt gebruik van lambda-expressies en functionele interfaces voor gegevensverwerking. In plaats van de imperatieve aanpak met lussen, beschrijf je wat er met de gegevens moet gebeuren:
Main.java
1234567891011121314package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }
Deze code maakt een stream van een lijst met fruitsoorten, zet de strings om naar hoofdletters met behulp van map(), en slaat de eerste drie elementen over met skip(). Het resultaat wordt verzameld in een nieuwe lijst en afgedrukt, beginnend vanaf het vierde element.
Onveranderlijkheid van gegevens
De Stream API wijzigt de oorspronkelijke gegevens niet. Alle bewerkingen creëren een nieuwe stream of geven een resultaat terug zonder de collectie of array te wijzigen. Dit verhoogt de gegevensveiligheid en voorkomt onverwachte neveneffecten.
Main.java
12345678910111213package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }
De Stream API filtert de lijst namen om een nieuwe stream, updateNames, te creëren die alleen elementen bevat die beginnen met de letter A. De oorspronkelijke lijst namen blijft echter ongewijzigd, omdat de Stream API de gegevens niet direct wijzigt, wat gegevensveiligheid waarborgt en neveneffecten voorkomt.
Streams zijn slechts één keer te gebruiken
Een stream kan slechts één keer worden gebruikt. Nadat een terminale bewerking is uitgevoerd, is de stream niet langer beschikbaar voor verdere verwerking.
Main.java
123456789101112package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }
Hier wordt een stream gemaakt van een lijst met strings en wordt elk element naar de console geprint. Nadat de stream voor de eerste keer is gebruikt, kan deze niet opnieuw worden gebruikt, wat een fout veroorzaakt als u probeert opnieuw forEach() aan te roepen.
Parallelle verwerking
De Stream API ondersteunt parallelle streams, waardoor snellere gegevensverwerking op multi-core systemen mogelijk is. Dit wordt uitgebreider besproken hier
Main.java
1234567891011package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }
Deze code maakt een parallelle stream van een lijst met getallen en print elk element naar de console. Door gebruik te maken van parallelStream() wordt parallelle verwerking van de lijstelementen mogelijk, wat de uitvoering kan versnellen bij het werken met grote datasets.
Codezuiverheid en Leesbaarheid
Het gebruik van de Stream API maakt de code meer declaratief. In plaats van te beschrijven hoe een taak moet worden uitgevoerd (zoals met lussen), wordt beschreven wat precies moet gebeuren. Dit verhoogt de leesbaarheid en vereenvoudigt het onderhoud van de code.
Voorbeeld met een lus:
List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
Voorbeeld met Stream API:
List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);
In het eerste lusvoorbeeld beschrijven we expliciet hoe we door de lijst moeten itereren en de elementen moeten afdrukken, terwijl we in het tweede voorbeeld met de Stream API eenvoudig aangeven wat er moet gebeuren: itereren door de elementen en deze afdrukken. Dit maakt de code meer declaratief en leesbaar.
Bedankt voor je feedback!