L'API Java Stream è una parte fondamentale del pacchetto java.util.stream introdotto in Java 8. Questa API offre una potente e flessibile astrazione per eseguire operazioni di elaborazione dei dati su sequenze di elementi, come collezioni, array o altre fonti di dati.
Le principali caratteristiche dell'API Java Stream includono:
Pipeline di Operazioni: Con Java Stream, è possibile creare una sequenza di operazioni su un flusso di dati. Queste operazioni possono includere filtraggio, mappatura, ordinamento, raggruppamento e altro. Le operazioni vengono eseguite in una sequenza logica, formando una "pipeline" di operazioni.
Lazy Evaluation: Un aspetto chiave della Stream API è l'evaluation lazy. Ciò significa che le operazioni sulla pipeline non vengono eseguite immediatamente al momento della loro definizione, ma vengono posticipate fino a quando il risultato finale è effettivamente richiesto. Questo può migliorare l'efficienza e ridurre la complessità computazionale.
Parallelismo Semplificato: La Stream API semplifica l'esecuzione parallela di operazioni su flussi di dati. È possibile sfruttare facilmente i processori multi-core per ottenere prestazioni migliori in caso di grandi quantità di dati.
Interoperabilità con le Collezioni: Le Stream API possono essere utilizzate con collezioni Java esistenti, come liste, insiemi e mappe. È possibile convertire facilmente una collezione in uno stream o viceversa.
Operazioni Terminali: Una pipeline Stream deve terminare con un'operazione terminale, come forEach, collect, reduce, o count, per ottenere un risultato concreto. Queste operazioni generano un risultato o un effetto collaterale.
In questo articolo, esploreremo alcune delle funzioni comunemente utilizzate all'interno di questa API, fornendo esempi pratici per illustrare come siano applicate.
filter(Predicate predicate)
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// Result: [2, 4, 6]
map(Function<T, R> mapper)
List names = Arrays.asList("Alice", "Bob", "Charlie");
List nameLengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
// Result: [5, 3, 7]
flatMap(Function<T, Stream> mapper)
List nestedLists = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4, 5),
Arrays.asList(6)
);
List flattenedList = nestedLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
// Result: [1, 2, 3, 4, 5, 6]
collect(Collector<T, A, R> collector)
List words = Arrays.asList("Hello", "Stream", "API");
String concatenated = words.stream()
.collect(Collectors.joining(" "));
// Result: "Hello Stream API"
forEach(Consumer action)
List numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.forEach(num -> System.out.print(num + " "));
// Output: 1 2 3 4 5
reduce(T identity, BinaryOperator accumulator)
List numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
// Result: 15
sorted() or sorted(Comparator comparator)
List names = Arrays.asList("Alice", "Bob", "Charlie");
List sortedNames = names.stream()
.sorted()
.collect(Collectors.toList());
// Result: ["Alice", "Bob", "Charlie"]
distinct()
List numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5);
List distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
// Result: [1, 2, 3, 4, 5]
count()
List names = Arrays.asList("Alice", "Bob", "Charlie");
long count = names.stream()
.count(); // Result: 3
max(Comparator comparator) and min(Comparator comparator)
List numbers = Arrays.asList(5, 2, 8, 3, 1);
Optional max = numbers.stream()
.max(Integer::compareTo);
// Result: Optional[8]
anyMatch(Predicate predicate), allMatch(Predicate predicate), and noneMatch(Predicate predicate)
List numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0); // true
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0); // false
boolean noneOdd = numbers.stream().noneMatch(n -> n % 2 != 0); // false
findFirst() and findAny()
List numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional firstEven = numbers.stream()
.filter(n -> n % 2 == 0)
.findFirst();
// Result: Optional[2]
Optional anyEven = numbers.stream()
.filter(n -> n % 2 == 0)
.findAny();
// Result: Optional[2] (or any other even number)
limit(long maxSize) and skip(long n)
List numbers = Arrays.asList(1, 2, 3, 4, 5);
List limited = numbers.stream()
.limit(3)
.collect(Collectors.toList());
// Result: [1, 2, 3]
List skipped = numbers.stream()
.skip(2)
.collect(Collectors.toList());
// Result: [3, 4, 5]
groupBy(Function<T, K> classifier)
import java.util.*;
import java.util.stream.Collectors;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class GroupByExample {
public static void main(String[] args) {
List people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 25),
new Person("David", 30)
);
Map<Integer, List> peopleByAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
System.out.println(peopleByAge);
//Result {25=[Person{name='Alice', age=25}, Person{name='Charlie', age=25}],
//30=[Person{name='Bob', age=30}, Person{name='David', age=30}]}
}
}
partitionBy(Predicate predicate)
import java.util.*;
import java.util.stream.Collectors;
public class PartitionByExample {
public static void main(String[] args) {
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Map<Boolean, List> evenAndOdd = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println("Even numbers: " + evenAndOdd.get(true));
//Result Even numbers: [2, 4, 6, 8, 10]
System.out.println("Odd numbers: " + evenAndOdd.get(false));
//Result Odd numbers: [1, 3, 5, 7, 9]
}
}
toArray()
import java.util.*;
import java.util.stream.Collectors;
public class ToArrayExample {
public static void main(String[] args) {
List colors = Arrays.asList("Red", "Green", "Blue");
String[] colorArray = colors.stream()
.toArray(String[]::new);
System.out.println(Arrays.toString(colorArray));
//Result [Red, Green, Blue]
}
}
Queste sono solo alcune delle funzioni fondamentali offerte dalla Java Stream API. Queste funzioni rendono più semplice e concisa l'elaborazione dei dati in Java, consentendo di scrivere codice più leggibile ed efficiente.