English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Tutorial di Base Java

Controllo del flusso Java

Array Java

Java Orientato agli oggetti (I)

Java Orientato agli oggetti (II)

Java Orientato agli oggetti (III)

Gestione delle eccezioni Java

Java List

Java Queue (coda)

Map di Java

Set di Java

Input/Output (I/O) Java

Reader/Writer Java

Altri argomenti Java

Java 8 Stream

Nuove caratteristiche di Java 8

L'API Java 8 aggiunge una nuova astrazione chiamata Stream, che ti permette di trattare i dati in modo dichiarativo.

Stream utilizza un modo intuitivo simile a SQL per interrogare i dati nel database per fornire un'alta astrazione delle operazioni e delle espressioni su Java Collection.

L'API Stream può aumentare notevolmente la produttività dei programmatori Java, permettendo loro di scrivere codice efficiente, pulito e semplice.

Questo stile considera l'insieme degli elementi da trattare come un flusso, che viene trasportato attraverso un tubo e può essere trattato nei nodi del tubo, ad esempio filtraggio, ordinamento, aggregazione, ecc.

Il flusso di elementi passa attraverso il trattamento delle operazioni intermedie (operazioni intermedie) e alla fine riceve i risultati del trattamento precedente dall'operazione finale (operazione finale).

+--------------------+       +------+   +------+   +---+   +-------+
| stream di elementi +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

Il seguente flusso può essere convertito in codice Java come segue:

List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();

Cos'è Stream?

Stream (flusso) è una coda di elementi provenienti da una fonte di dati e supporta operazioni di aggregazione

  • Coda degli elementi Gli elementi sono oggetti di tipo specifico, che formano una coda. Java non memorizza gli elementi tramite Stream, ma li calcola su richiesta.

  • Sorgente dei dati La fonte del flusso. Può essere una raccolta, un array, un canale I/O, un generatore generator, ecc.

  • Operazioni di aggregazione Operazioni simili a SQL, come filter, map, reduce, find, match, sorted, ecc.

Diversamente dalle operazioni Collection precedenti, le operazioni Stream hanno due caratteristiche fondamentali:

  • Pipelining: Le operazioni intermedie restituiscono sempre l'oggetto flusso stesso. In questo modo, più operazioni possono essere concatenate in una pipeline, come lo stile di flusso (fluent style). Questo permette di ottimizzare le operazioni, come l'esecuzione differita (laziness) e il cortocircuito (short-circuiting).

  • Iterazione interna: Prima la scansione della raccolta era fatta tramite Iterator o For-Each, esplicitamente fuori dalla raccolta, questo si chiama iterazione esterna. Stream fornisce un modo di iterazione interna, realizzato tramite il modello Visitor (Visitaore).

Generazione del flusso

In Java 8, l'interfaccia della raccolta ha due metodi per generare flussi:

  • stream() − Crea un flusso sequenziale per la raccolta.

  • parallelStream()  − Crea un flusso parallelo per la raccolta.

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

forEach

Stream fornisce un nuovo metodo 'forEach' per iterare ogni elemento del flusso di dati. Il seguente frammento di codice utilizza forEach per esportare 10 numeri casuali:

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

map

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map(i -> i*i).distinct().collect(Collectors.toList());

filter

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();

limit

limit 方法用于获取指定数量的流。以下代码片段使用 limit 方法打印出 10 条数据:

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

sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

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

并行(parallel)程序

parallelStream 是流并行处理程序的替代方法。以下示例我们使用 parallelStream 来输出空字符串的数量:

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();

我们可以很容易地在顺序运行和并行直接切换。

Collectors

Collectors 类实现了许多归约操作,例如将流转换为集合和聚合元素。Collectors 可用于返回列表或字符串:

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("Elenco filtrato: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Stringa combinata: " + mergedString);

Statistiche

Inoltre, alcuni collector che generano risultati statistici sono molto utili. Questi sono principalmente utilizzati per tipi di base come int, double, long, e possono essere utilizzati per generare risultati statistici simili a quelli seguenti.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
 
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
 
System.out.println("Numero massimo nella lista: " + stats.getMax());
System.out.println("Numero minimo nella lista: " + stats.getMin());
System.out.println("Somma di tutti i numeri: " + stats.getSum());
System.out.println("Media: " + stats.getAverage());

Esempio completo di Stream

Inserisci il seguente codice nel file 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("Utilizzando Java 7: ");
        
      // Calcolo delle stringhe vuote
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("Elenco: " + strings);
      long count = getCountEmptyStringUsingJava7(strings);
        
      System.out.println("Il numero di caratteri vuoti è: " + count);
      count = getCountLength2UsingJava7(strings);
        
      System.out.println("Numero di stringhe con lunghezza 3: " + count);
        
      // Elimina le stringhe vuote
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("Lista filtrata: " + filtered);
        
      // Elimina le stringhe vuote e unisci con virgola
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("Stringa combinata: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        
      // Ottieni i quadrati degli elementi dell'elenco
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("Elenco dei quadrati: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        
      System.out.println("Lista: " + integers);
      System.out.println("Numero massimo dell'elenco: " + getMax(integers));
      System.out.println("Numero minimo dell'elenco: " + getMin(integers));
      System.out.println("Somma di tutti i numeri: " + getSum(integers));
      System.out.println("Media: " + getAverage(integers));
      System.out.println("Numeri casuali: ");
        
      // Output di 10 numeri casuali
      Random random = new Random();
        
      for(int i=0; i < 10; i++){
         System.out.println(random.nextInt());
      }
        
      System.out.println("Utilizzando Java 8: ");
      System.out.println("Elenco: " + strings);
        
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("Il numero di stringhe vuote è: " + count);
        
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("Numero di stringhe con lunghezza 3: " + count);
        
      filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
      System.out.println("Lista filtrata: " + filtered);
        
      mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("Stringa combinata: " + mergedString);
        
      squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
      System.out.println("Elenco dei quadrati: " + squaresList);
      System.out.println("Lista: " + integers);
        
      IntSummaryStatistics stats = integers.stream().mapToInt((x) -> x).summaryStatistics();
        
      System.out.println("Numero massimo nella lista: " + stats.getMax());
      System.out.println("Numero minimo nella lista: " + stats.getMin());
      System.out.println("Somma di tutti i numeri: " + stats.getSum());
      System.out.println("Media: " + stats.getAverage());
      System.out.println("Numeri casuali: ");
        
      random.ints().limit(10).sorted().forEach(System.out::println);
        
      // Elaborazione parallela
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("空字符串的数量为: " + count);}
   }
    
   private static int getCountEmptyStringUsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.isEmpty()){
            count++;
         }
      }
      return count;
   }
    
   private static int getCountLength2UsingJava7(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();
   }
}

Eseguire lo script sopra, il risultato di output è:

$ javac Java8Tester.java 
$ java Java8Tester
Usare Java 7: 
Elenco: [abc, , bc, efg, abcd, , jkl]
Numero di caratteri vuoti: 2
Il numero di stringhe di lunghezza 3 è: 3
Elenco filtrato: [abc, bc, efg, abcd, jkl]
Unione di stringhe: abc, bc, efg, abcd, jkl
Elenco dei quadrati: [9, 4, 49, 25]
Elenco: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Numero più grande nella lista: 19
Numero più piccolo nella lista: 1
Somma di tutti i numeri: 85
Media: 9
Numero casuale: 
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
Usando Java 8: 
Elenco: [abc, , bc, efg, abcd, , jkl]
Il numero di stringhe vuote è: 2
Il numero di stringhe di lunghezza 3 è: 3
Elenco filtrato: [abc, bc, efg, abcd, jkl]
Unione di stringhe: abc, bc, efg, abcd, jkl
Elenco di quadrati: [9, 4, 49, 25]
Elenco: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Numero più grande nella lista: 19
Numero più piccolo nella lista: 1
Somma di tutti i numeri: 85
Media: 9.444444444444445
Numero casuale: 
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
Il numero di stringhe vuote è: 2

Nuove caratteristiche di Java 8