Java 8 - Streams
Stream is een nieuwe abstracte laag die in Java 8 is geïntroduceerd. Met stream kunt u gegevens op een declaratieve manier verwerken, vergelijkbaar met SQL-instructies. Beschouw bijvoorbeeld de volgende SQL-instructie.
SELECT max(salary), employee_id, employee_name FROM Employee
De bovenstaande SQL-expressie retourneert automatisch de gegevens van de maximaal bezoldigde werknemer, zonder enige berekening aan de kant van de ontwikkelaar. Met behulp van het verzamelingsframework in Java moet een ontwikkelaar lussen gebruiken en herhaalde controles uitvoeren. Een andere zorg is efficiëntie; aangezien multi-coreprocessors gemakkelijk beschikbaar zijn, moet een Java-ontwikkelaar parallelle codeverwerking schrijven die behoorlijk foutgevoelig kan zijn.
Om dergelijke problemen op te lossen, introduceerde Java 8 het concept van stream waarmee de ontwikkelaar gegevens declaratief kan verwerken en multicore-architectuur kan gebruiken zonder dat er specifieke code voor hoeft te worden geschreven.
Wat is streamen?
Stream vertegenwoordigt een reeks objecten uit een bron, die aggregatiebewerkingen ondersteunt. Hieronder volgen de kenmerken van een stream −
-
Opeenvolging van elementen − Een stream levert een reeks elementen van een specifiek type op een sequentiële manier. Een stream krijgt/berekent elementen op aanvraag. Het slaat nooit de elementen op.
-
Bron − Stream gebruikt verzamelingen, arrays of I/O-bronnen als invoerbron.
-
Totale bewerkingen − Stream ondersteunt geaggregeerde bewerkingen zoals filteren, in kaart brengen, beperken, verkleinen, vinden, matchen, enzovoort.
-
Pijpvoering − De meeste stroombewerkingen retourneren de stroom zelf, zodat hun resultaat kan worden gepijplijnd. Deze bewerkingen worden tussenbewerkingen genoemd en hun functie is om invoer te nemen, deze te verwerken en de uitvoer terug te sturen naar het doel. collect()-methode is een terminalbewerking die normaal gesproken aanwezig is aan het einde van de pipelining-bewerking om het einde van de stream te markeren.
-
Automatische herhalingen − Streambewerkingen voeren de iteraties intern uit over de geleverde bronelementen, in tegenstelling tot collecties waar expliciete iteratie vereist is.
Stremen genereren
Met Java 8 heeft de Collection-interface twee methoden om een stream te genereren.
-
stream() − Retourneert een sequentiële stream waarbij de verzameling als bron wordt beschouwd.
-
parallelStream() − Retourneert een parallelle stream waarbij de verzameling als bron wordt beschouwd.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
voor elk
Stream heeft een nieuwe methode 'forEach' geboden om elk element van de stream te herhalen. Het volgende codesegment laat zien hoe u 10 willekeurige getallen kunt afdrukken met forEach.
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
kaart
De 'map'-methode wordt gebruikt om elk element toe te wijzen aan het bijbehorende resultaat. Het volgende codesegment drukt unieke vierkanten van getallen af met behulp van de kaart.
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of unique squares List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
De ‘filter’ methode wordt gebruikt om elementen te verwijderen op basis van een criterium. Het volgende codesegment drukt een telling van lege tekenreeksen af met behulp van filter.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string int count = strings.stream().filter(string -> string.isEmpty()).count();
limiet
De 'limiet'-methode wordt gebruikt om de stroom te verkleinen. Het volgende codesegment laat zien hoe u 10 willekeurige getallen kunt afdrukken met limiet.
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
gesorteerd
De ‘gesorteerde’ methode wordt gebruikt om de stream te sorteren. Het volgende codesegment laat zien hoe u 10 willekeurige getallen in een gesorteerde volgorde kunt afdrukken.
Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);
Parallelle verwerking
parallelStream is het alternatief van stream voor parallelle verwerking. Bekijk het volgende codesegment dat een aantal lege strings afdrukt met parallelStream.
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); //get count of empty string long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
Het is heel eenvoudig om te schakelen tussen sequentiële en parallelle streams.
Verzamelaars
Collectors worden gebruikt om het resultaat van verwerking op de elementen van een stroom te combineren. Verzamelaars kunnen worden gebruikt om een lijst of een tekenreeks te retourneren.
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString);
Statistieken
Met Java 8 worden statistiekenverzamelaars geïntroduceerd om alle statistieken te berekenen wanneer streamverwerking wordt gedaan.
List numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("Highest number in List : " + stats.getMax()); System.out.println("Lowest number in List : " + stats.getMin()); System.out.println("Sum of all numbers : " + stats.getSum()); System.out.println("Average of all numbers : " + stats.getAverage());
Streamvoorbeeld
Maak het volgende Java-programma met een editor naar keuze, bijvoorbeeld C:\> JAVA.
Java8Tester.java
Live demoimport java.util.ArrayList; import java.util.Arrays; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Random; import java.util.stream.Collectors; import java.util.Map; public class Java8Tester { public static void main(String args[]) { System.out.println("Using Java 7: "); // Count empty strings List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); System.out.println("List: " +strings); long count = getCountEmptyStringUsingJava7(strings); System.out.println("Empty Strings: " + count); count = getCountLength3UsingJava7(strings); System.out.println("Strings of length 3: " + count); //Eliminate empty string List<String> filtered = deleteEmptyStringsUsingJava7(strings); System.out.println("Filtered List: " + filtered); //Eliminate empty string and join using comma. String mergedString = getMergedStringUsingJava7(strings,", "); System.out.println("Merged String: " + mergedString); List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); //get list of square of distinct numbers List<Integer> squaresList = getSquares(numbers); System.out.println("Squares List: " + squaresList); List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19); System.out.println("List: " +integers); System.out.println("Highest number in List : " + getMax(integers)); System.out.println("Lowest number in List : " + getMin(integers)); System.out.println("Sum of all numbers : " + getSum(integers)); System.out.println("Average of all numbers : " + getAverage(integers)); System.out.println("Random Numbers: "); //print ten random numbers Random random = new Random(); for(int i = 0; i < 10; i++) { System.out.println(random.nextInt()); } System.out.println("Using Java 8: "); System.out.println("List: " +strings); count = strings.stream().filter(string->string.isEmpty()).count(); System.out.println("Empty Strings: " + count); count = strings.stream().filter(string -> string.length() == 3).count(); System.out.println("Strings of length 3: " + count); filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList()); System.out.println("Filtered List: " + filtered); mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("Merged String: " + mergedString); squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList()); System.out.println("Squares List: " + squaresList); System.out.println("List: " +integers); IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics(); System.out.println("Highest number in List : " + stats.getMax()); System.out.println("Lowest number in List : " + stats.getMin()); System.out.println("Sum of all numbers : " + stats.getSum()); System.out.println("Average of all numbers : " + stats.getAverage()); System.out.println("Random Numbers: "); random.ints().limit(10).sorted().forEach(System.out::println); //parallel processing count = strings.parallelStream().filter(string -> string.isEmpty()).count(); System.out.println("Empty Strings: " + count); } private static int getCountEmptyStringUsingJava7(List<String> strings) { int count = 0; for(String string: strings) { if(string.isEmpty()) { count++; } } return count; } private static int getCountLength3UsingJava7(List<String> strings) { int count = 0; for(String string: strings) { if(string.length() == 3) { count++; } } return count; } private static List<String> deleteEmptyStringsUsingJava7(List<String> strings) { List<String> filteredList = new ArrayList<String>(); for(String string: strings) { if(!string.isEmpty()) { filteredList.add(string); } } return filteredList; } private static String getMergedStringUsingJava7(List<String> strings, String separator) { StringBuilder stringBuilder = new StringBuilder(); for(String string: strings) { if(!string.isEmpty()) { stringBuilder.append(string); stringBuilder.append(separator); } } String mergedString = stringBuilder.toString(); return mergedString.substring(0, mergedString.length()-2); } private static List<Integer> getSquares(List<Integer> numbers) { List<Integer> squaresList = new ArrayList<Integer>(); for(Integer number: numbers) { Integer square = new Integer(number.intValue() * number.intValue()); if(!squaresList.contains(square)) { squaresList.add(square); } } return squaresList; } private static int getMax(List<Integer> numbers) { int max = numbers.get(0); for(int i = 1;i < numbers.size();i++) { Integer number = numbers.get(i); if(number.intValue() > max) { max = number.intValue(); } } return max; } private static int getMin(List<Integer> numbers) { int min = numbers.get(0); for(int i= 1;i < numbers.size();i++) { Integer number = numbers.get(i); if(number.intValue() < min) { min = number.intValue(); } } return min; } private static int getSum(List numbers) { int sum = (int)(numbers.get(0)); for(int i = 1;i < numbers.size();i++) { sum += (int)numbers.get(i); } return sum; } private static int getAverage(List<Integer> numbers) { return getSum(numbers) / numbers.size(); } }
Verifieer het resultaat
Stel de klas samen met javac compiler als volgt −
C:\JAVA>javac Java8Tester.java
Voer nu de Java8Tester als volgt uit −
C:\JAVA>java Java8Tester
Het zou het volgende resultaat moeten opleveren −
Using Java 7: List: [abc, , bc, efg, abcd, , jkl] Empty Strings: 2 Strings of length 3: 3 Filtered List: [abc, bc, efg, abcd, jkl] Merged String: abc, bc, efg, abcd, jkl Squares List: [9, 4, 49, 25] List: [1, 2, 13, 4, 15, 6, 17, 8, 19] Highest number in List : 19 Lowest number in List : 1 Sum of all numbers : 85 Average of all numbers : 9 Random Numbers: -1279735475 903418352 -1133928044 -1571118911 628530462 18407523 -881538250 -718932165 270259229 421676854 Using Java 8: List: [abc, , bc, efg, abcd, , jkl] Empty Strings: 2 Strings of length 3: 3 Filtered List: [abc, bc, efg, abcd, jkl] Merged String: abc, bc, efg, abcd, jkl Squares List: [9, 4, 49, 25] List: [1, 2, 13, 4, 15, 6, 17, 8, 19] Highest number in List : 19 Lowest number in List : 1 Sum of all numbers : 85 Average of all numbers : 9.444444444444445 Random Numbers: -1009474951 -551240647 -2484714 181614550 933444268 1227850416 1579250773 1627454872 1683033687 1798939493 Empty Strings: 2
Java