The Java Streams API (introduced in Java 8) provides a modern, functional-style way to process collections of data. It allows you to work with sequences of elements (like List
, Set
, or arrays) using declarative operations such as filtering, mapping, reducing, collecting, and more, while supporting parallel execution.
Key Concepts
- Stream: A sequence of elements supporting sequential and parallel operations.
- Intermediate operations: Transform a stream into another stream (lazy operations). Examples:
filter()
,map()
,sorted()
. - Terminal operations: Produce a result or a side-effect and end the stream pipeline. Examples:
collect()
,forEach()
,reduce()
.
Examples
1. Creating Streams
import java.util.*;
import java.util.stream.*;
public class StreamExamples {
public static void main(String[] args) {
// From a list
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream1 = names.stream();
// From an array
String[] arr = {"one", "two", "three"};
Stream<String> stream2 = Arrays.stream(arr);
// Using Stream.of
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
// Infinite stream (example: odd numbers)
Stream<Integer> oddNumbers = Stream.iterate(1, n -> n + 2);
}
}
2. Filtering
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println);
// Output: Alice
3. Mapping
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
// Output: ALICE, BOB, CHARLIE
4. Sorting
List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
names.stream()
.sorted()
.forEach(System.out::println);
// Output: Alice, Bob, Charlie
5. Collecting Results
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> filtered = names.stream()
.filter(n -> n.length() > 3)
.collect(Collectors.toList());
System.out.println(filtered);
// Output: [Alice, Charlie, David]
6. Reduce (Aggregation)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println(sum);
// Output: 15
7. Parallel Streams
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum();
System.out.println(sum);
// Output: 15
8. Grouping
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Anna");
Map<Character, List<String>> grouped =
names.stream()
.collect(Collectors.groupingBy(name -> name.charAt(0)));
System.out.println(grouped);
// Output: {A=[Alice, Anna], B=[Bob], C=[Charlie], D=[David]}
✅ When to use Streams?
- When you want concise, readable, functional-style data processing.
- When parallelism could improve performance (e.g., large datasets).
- When you don’t need to modify the original collection.