Java 8 - Stream

Stream è un nuovo livello astratto introdotto in Java 8. Utilizzando stream, è possibile elaborare i dati in modo dichiarativo simile alle istruzioni SQL. Ad esempio, considera la seguente istruzione SQL.

SELECT max(salary), employee_id, employee_name FROM Employee

L'espressione SQL sopra riportata restituisce automaticamente i dettagli del massimo dipendente stipendiato, senza eseguire alcun calcolo da parte dello sviluppatore. Utilizzando il framework delle raccolte in Java, uno sviluppatore deve utilizzare i loop ed eseguire controlli ripetuti. Un'altra preoccupazione è l'efficienza; poiché i processori multi-core sono disponibili a proprio agio, uno sviluppatore Java deve scrivere un'elaborazione del codice parallela che può essere piuttosto soggetta a errori.

Per risolvere tali problemi, Java 8 ha introdotto il concetto di flusso che consente allo sviluppatore di elaborare i dati in modo dichiarativo e di sfruttare l'architettura multicore senza la necessità di scrivere alcun codice specifico per esso.

Cos'è Stream?

Stream rappresenta una sequenza di oggetti da un'origine, che supporta le operazioni di aggregazione. Di seguito sono riportate le caratteristiche di uno Stream:

  • Sequence of elements- Un flusso fornisce un insieme di elementi di tipo specifico in modo sequenziale. Un flusso ottiene / calcola elementi su richiesta. Non memorizza mai gli elementi.

  • Source - Stream accetta raccolte, array o risorse I / O come origine di input.

  • Aggregate operations - Stream supporta operazioni aggregate come filtro, mappa, limite, riduzione, trova, corrispondenza e così via.

  • Pipelining- La maggior parte delle operazioni di flusso restituisce il flusso stesso in modo che il risultato possa essere pipeline. Queste operazioni sono chiamate operazioni intermedie e la loro funzione è quella di prendere input, elaborarli e restituire l'output alla destinazione. Il metodo collect () è un'operazione terminale che è normalmente presente alla fine dell'operazione di pipelining per contrassegnare la fine del flusso.

  • Automatic iterations - Le operazioni di flusso eseguono le iterazioni internamente sugli elementi di origine forniti, a differenza delle raccolte in cui è richiesta un'iterazione esplicita.

Generazione di flussi

Con Java 8, l'interfaccia Collection ha due metodi per generare un flusso.

  • stream() - Restituisce un flusso sequenziale considerando la raccolta come fonte.

  • parallelStream() - Restituisce un flusso parallelo considerando la raccolta come origine.

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

per ciascuno

Stream ha fornito un nuovo metodo "forEach" per iterare ogni elemento dello stream. Il seguente segmento di codice mostra come stampare 10 numeri casuali usando forEach.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

carta geografica

Il metodo "map" viene utilizzato per mappare ogni elemento al risultato corrispondente. Il seguente segmento di codice stampa quadrati di numeri univoci utilizzando map.

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());

filtro

Il metodo "filtro" viene utilizzato per eliminare gli elementi in base a un criterio. Il seguente segmento di codice stampa un conteggio delle stringhe vuote utilizzando il filtro.

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

//get count of empty string
int count = strings.stream().filter(string -> string.isEmpty()).count();

limite

Il metodo "limit" viene utilizzato per ridurre le dimensioni del flusso. Il seguente segmento di codice mostra come stampare 10 numeri casuali utilizzando limit.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

smistato

Il metodo "ordinato" viene utilizzato per ordinare il flusso. Il seguente segmento di codice mostra come stampare 10 numeri casuali in un ordine ordinato.

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

Elaborazione parallela

parallelStream è l'alternativa di stream per l'elaborazione parallela. Dai un'occhiata al seguente segmento di codice che stampa un conteggio di stringhe vuote usando 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();

È molto facile passare tra flussi sequenziali e paralleli.

Collezionisti

I servizi di raccolta vengono utilizzati per combinare il risultato dell'elaborazione sugli elementi di un flusso. I servizi di raccolta possono essere utilizzati per restituire un elenco o una stringa.

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);

Statistiche

Con Java 8, i raccoglitori di statistiche vengono introdotti per calcolare tutte le statistiche quando viene eseguita l'elaborazione del flusso.

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());

Esempio di flusso

Crea il seguente programma Java utilizzando qualsiasi editor di tua scelta, ad esempio C: \> JAVA.

Java8Tester.java

import 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();
   }
}

Verifica il risultato

Compila la classe usando javac compilatore come segue -

C:\JAVA>javac Java8Tester.java

Ora esegui Java8Tester come segue:

C:\JAVA>java Java8Tester

Dovrebbe produrre il seguente risultato:

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