The Java Streams API, introduced in Java 8, brings the power of functional programming to collections. It enables developers to process data in a declarative, readable, and concise way using pipelines of transformations and operations.
1. What Is a Stream in Java?
A Stream is a sequence of elements supporting sequential and parallel aggregate operations. It is not a data structure but a view of a data source (like collections, arrays, or I/O channels).
2. Stream Pipeline Components
A stream pipeline consists of:
- Source: A collection or array
- Intermediate operations: Transform the stream (
filter
, map
, sorted
, etc.) - Terminal operation: Produces a result (
collect
, forEach
, reduce
, etc.)
3. Basic Stream Example
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.filter(name -> name.startsWith("A"))
.map(String::toUpperCase)
.forEach(System.out::println);
Output:
nginx
ALICE
4. Common Intermediate Operations
filter(Predicate<T>)
: Filters elementsmap(Function<T, R>)
: Transforms each elementsorted()
: Sorts the streamdistinct()
: Removes duplicateslimit(n)
: Truncates to the first n
elements
5. Common Terminal Operations
forEach()
: Performs an action for each elementcollect()
: Converts the stream into a collectionreduce()
: Combines elements into a single resultcount()
: Counts elementsanyMatch()
, allMatch()
: Checks conditions
Example:
java
int sum = Arrays.asList(1, 2, 3, 4).stream()
.reduce(0, Integer::sum); // 10
6. Collecting Results
Using Collectors
:
java
List<String> filtered = names.stream()
.filter(name -> name.length() > 3)
.collect(Collectors.toList());
Other collectors: toSet()
, joining()
, groupingBy()
, partitioningBy()
7. Parallel Streams
For large data sets, use parallel processing:
java
names.parallelStream()
.map(String::toLowerCase)
.forEach(System.out::println);
Note: Use cautiously—parallel streams introduce multithreading and may not always improve performance.
8. Stream vs Traditional Loop
Loop:
java
for (String name : names) {
if (name.length() > 3) {
System.out.println(name.toUpperCase());
}
}
Stream:
java
names.stream()
.filter(n -> n.length() > 3)
.map(String::toUpperCase)
.forEach(System.out::println);
Streams offer cleaner and more expressive alternatives.
9. Best Practices
- Avoid using stateful lambdas (like modifying external variables).
- Prefer method references for clarity.
- Use
.collect()
wisely to avoid unnecessary processing. - Don’t overuse
.parallelStream()
unless benchmarking proves benefit.
The Java Streams API brings elegant, functional-style data processing to Java. Mastering it makes your code more expressive and less error-prone, especially when dealing with collections and data transformations.