Java · Collections · Topic 10
Streams API
Build declarative Java data pipelines with stream creation, transformation, reduction, matching, numeric streams, and collectors.
Step 1 of 30
10.1 Introduction
Explain declarative stream processing and its common operations.
import java.util.Arrays;
import java.util.List;
public class StreamsIntroductionDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(10,15,20,25,30);
numbers.stream().filter(n -> n % 2 == 0).forEach(System.out::println);
}
}10
20
30Stream operations
- Filtering
- Transforming
- Sorting
- Removing duplicates
- Counting
- Aggregation
- Grouping
- Collecting
Check your understanding: Which operation selects elements satisfying a condition?
filter().
Step 2 of 30
10.2 Stream Is Not a Data Structure
Distinguish processing from storage and observe source immutability.
import java.util.*;
import java.util.stream.Collectors;
public class StreamSourceDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5,2,8,1);
List<Integer> sorted = numbers.stream().sorted().collect(Collectors.toList());
System.out.println(numbers);
System.out.println(sorted);
}
}[5, 2, 8, 1]
[1, 2, 5, 8]Possible sources
- Collection
- Array
- File
- Generated values
Check your understanding: Does a stream itself store the elements?
No.
Step 3 of 30
10.3 Stream Pipeline
Identify source, intermediate operations, and a terminal operation.
import java.util.*;
import java.util.stream.Collectors;
public class StreamPipelineDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Java", "C", "Python", "Go");
List<String> result = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
System.out.println(result);
}
}[JAVA, PYTHON]| Stage | Role | Examples |
|---|---|---|
| Source | Provides data | names.stream() |
| Intermediate | Transforms or filters | filter(), map(), sorted() |
| Terminal | Produces result or action | collect(), forEach(), count(), reduce() |
Check your understanding: Which operation completes the shown pipeline?
collect().
Step 4 of 30
10.4 Creating Streams
Create streams from collections, arrays, values, generators, and iterative sequences.
import java.util.*;
import java.util.stream.*;
public class StreamCreationDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Amit", "Neha");
System.out.println(names.stream().count());
System.out.println(Arrays.stream(new String[]{"Java","Python"}).count());
System.out.println(Stream.of(10,20,30,40).count());
Stream.iterate(1, n -> n + 1).limit(5).forEach(System.out::println);
}
}2
2
4
1
2
3
4
5Stream<String> empty = Stream.empty();
Stream<Double> random = Stream.generate(Math::random).limit(5);Check your understanding: Why should generate() usually be followed by limit() in examples?
generate() is otherwise unbounded.
Step 5 of 30
10.5 Intermediate Operations
Recognize lazy operations that return another Stream.
Important intermediate operations
- filter()
- map()
- flatMap()
- sorted()
- distinct()
- limit()
- skip()
- peek()
Check your understanding: Does filter() immediately traverse the source by itself?
No.
Step 6 of 30
10.6 filter()
Select elements with a Predicate.
import java.util.*;
public class FilterDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(10,15,20,25,30);
numbers.stream().filter(n -> n > 20).forEach(System.out::println);
}
}25
30Check your understanding: Which values greater than 20 remain from 10,15,20,25,30?
25 and 30.
Step 7 of 30
10.7 map()
Transform every stream element using a Function.
import java.util.*;
public class MapStreamDemo {
public static void main(String[] args) {
Arrays.asList(1,2,3,4).stream().map(n -> n*n).forEach(System.out::println);
Arrays.asList("Java","Python").stream().map(String::toUpperCase).forEach(System.out::println);
}
}1
4
9
16
JAVA
PYTHONCheck your understanding: What are the squares of 1,2,3,4?
1,4,9,16.
Step 8 of 30
10.8 flatMap()
Flatten nested element streams into one stream.
import java.util.*;
import java.util.stream.Collectors;
public class FlatMapDemo {
public static void main(String[] args) {
List<List<Integer>> lists = Arrays.asList(
Arrays.asList(1,2), Arrays.asList(3,4), Arrays.asList(5,6));
List<Integer> result = lists.stream().flatMap(List::stream).collect(Collectors.toList());
System.out.println(result);
}
}[1, 2, 3, 4, 5, 6]Check your understanding: What is the flattened form of [1,2], [3,4], [5,6]?
[1,2,3,4,5,6].
Step 9 of 30
10.9 sorted()
Sort stream elements naturally or with a Comparator.
numbers.stream().sorted();
numbers.stream().sorted(Comparator.reverseOrder());
names.stream().sorted(Comparator.comparingInt(String::length));Check your understanding: How is descending numeric order requested?
sorted(Comparator.reverseOrder()).
Step 10 of 30
10.10 distinct()
Remove duplicates using object equality.
import java.util.*;
public class DistinctDemo {
public static void main(String[] args) {
Arrays.asList(10,20,10,30,20).stream().distinct().forEach(System.out::println);
}
}10
20
30Check your understanding: What remains from 10,20,10,30,20?
10,20,30 in encounter order.
Step 11 of 30
10.11 limit()
Take at most the first n encountered elements.
numbers.stream().limit(3).forEach(System.out::println);Check your understanding: How many elements can limit(3) emit?
At most three.
Step 12 of 30
10.12 skip()
Ignore the first n elements and combine skip with limit for pages.
numbers.stream().skip(2).forEach(System.out::println);
numbers.stream().skip(5).limit(5).forEach(System.out::println);Check your understanding: What does skip(5).limit(5) select?
Up to five elements after ignoring the first five.
Step 13 of 30
10.13 peek()
Observe elements while they continue through a pipeline.
numbers.stream()
.filter(n -> n % 2 == 0)
.peek(n -> System.out.println("Filtered: " + n))
.map(n -> n * n)
.forEach(System.out::println);Check your understanding: Does peek terminate a stream?
No.
Step 14 of 30
10.14 Terminal Operations
Identify operations that consume and close a pipeline.
Terminal operations
- forEach()
- collect()
- reduce()
- count()
- min()
- max()
- anyMatch()
- allMatch()
- noneMatch()
- findFirst()
- findAny()
Check your understanding: Which terminal operation counts elements?
count().
Step 15 of 30
10.15 forEach()
Perform an action for every consumed element.
names.stream().forEach(System.out::println);Check your understanding: What method reference prints each name?
System.out::println.
Step 16 of 30
10.16 collect()
Gather stream elements into collection results.
import java.util.*;
import java.util.stream.Collectors;
public class CollectorsDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(10,15,20,25,30);
List<Integer> evens = numbers.stream().filter(n -> n%2==0).collect(Collectors.toList());
Set<Integer> unique = numbers.stream().collect(Collectors.toSet());
System.out.println(evens);
System.out.println(unique.size());
}
}[10, 20, 30]
5Check your understanding: Which collector produces a Set?
Collectors.toSet().
Step 17 of 30
10.17 count()
Count elements after optional filtering.
long count = numbers.stream().filter(n -> n > 20).count();
System.out.println(count); // 2Check your understanding: How many values exceed 20 in 10,15,20,25,30?
Two.
Step 18 of 30
10.18 min() and max()
Find extreme elements with a Comparator.
Optional<Integer> minimum = numbers.stream().min(Integer::compareTo);
Optional<Integer> maximum = numbers.stream().max(Integer::compareTo);
minimum.ifPresent(System.out::println);
maximum.ifPresent(System.out::println);Check your understanding: Why is Optional returned?
An empty stream has no minimum or maximum.
Step 19 of 30
10.19 Optional
Represent a result that may be absent and handle it safely.
Optional<Integer> result = numbers.stream().max(Integer::compareTo);
result.ifPresent(System.out::println);
int maximum = result.orElse(0);Check your understanding: What does orElse(0) provide when no value exists?
The default value 0.
Step 20 of 30
10.20 reduce()
Combine all elements into one accumulated result.
import java.util.*;
public class ReduceDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1,2,3,4);
System.out.println("Sum: " + numbers.stream().reduce(0, Integer::sum));
System.out.println("Product: " + numbers.stream().reduce(1, (a,b) -> a*b));
List<String> names = Arrays.asList("Java","C","Database");
System.out.println("Longest: " + names.stream()
.reduce((a,b) -> a.length() >= b.length() ? a : b).orElse(""));
}
}Sum: 10
Product: 24
Longest: DatabaseCheck your understanding: What identity should a multiplication reduction use?
1.
Step 21 of 30
10.21 Matching Operations
Test whether any, all, or no elements satisfy a Predicate.
| Method | Meaning |
|---|---|
| anyMatch() | At least one element matches |
| allMatch() | Every element matches |
| noneMatch() | No element matches |
boolean anyLarge = numbers.stream().anyMatch(n -> n > 50);
boolean allPositive = numbers.stream().allMatch(n -> n > 0);
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);Check your understanding: Which method succeeds when no element is negative?
noneMatch(n -> n < 0).
Step 22 of 30
10.22 Finding Operations
Find the first or any matching element through Optional.
Optional<Integer> first = numbers.stream().filter(n -> n > 20).findFirst();
Optional<Integer> any = numbers.stream().filter(n -> n > 20).findAny();Check your understanding: Which operation guarantees the first encountered match?
findFirst().
Step 23 of 30
10.23 Numeric Streams
Use primitive-specialized streams and understand range boundaries.
import java.util.stream.IntStream;
public class NumericStreamDemo {
public static void main(String[] args) {
System.out.println(IntStream.rangeClosed(1,10).sum());
IntStream.range(1,5).forEach(System.out::print);
System.out.println();
IntStream.rangeClosed(1,5).forEach(System.out::print);
}
}55
1234
12345Check your understanding: Does IntStream.range(1,5) include 5?
No; rangeClosed(1,5) includes it.
Step 24 of 30
10.24 Calculations Using Numeric Streams
Map boxed numbers to IntStream for sum, average, and maximum.
import java.util.*;
public class NumericCalculationDemo {
public static void main(String[] args) {
List<Integer> marks = Arrays.asList(70,80,90,60);
System.out.println("Total: " + marks.stream().mapToInt(Integer::intValue).sum());
System.out.println("Average: " + marks.stream().mapToInt(Integer::intValue).average().orElse(0));
System.out.println("Maximum: " + marks.stream().mapToInt(Integer::intValue).max().orElse(0));
}
}Total: 300
Average: 75.0
Maximum: 90Check your understanding: What is the average of 70,80,90,60?
75.0.
Step 25 of 30
10.25 Collectors
Identify common reduction, aggregation, grouping, and partitioning collectors.
Important collectors
- toList()
- toSet()
- joining()
- groupingBy()
- partitioningBy()
- counting()
- averagingInt()
- summingInt()
Check your understanding: Which collector divides elements into true and false groups?
partitioningBy().
Step 26 of 30
10.26 Joining Strings
Combine text elements with delimiters and optional boundaries.
import java.util.*;
import java.util.stream.Collectors;
public class JoiningDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Amit","Neha","Raj");
System.out.println(names.stream().collect(Collectors.joining(", ")));
System.out.println(names.stream().collect(Collectors.joining(", ", "[", "]")));
}
}Amit, Neha, Raj
[Amit, Neha, Raj]Check your understanding: What does joining(", ") produce for Amit, Neha, Raj?
Amit, Neha, Raj.
Step 27 of 30
10.27 Grouping Data
Group elements by a classifier key.
import java.util.*;
import java.util.stream.Collectors;
public class GroupingDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Amit","Raj","Neha","Riya","Ankit");
Map<Character,List<String>> grouped = names.stream()
.collect(Collectors.groupingBy(name -> name.charAt(0), TreeMap::new, Collectors.toList()));
System.out.println(grouped);
}
}{A=[Amit, Ankit], N=[Neha], R=[Raj, Riya]}Check your understanding: Which key groups Amit and Ankit together?
The character A.
Step 28 of 30
10.28 Partitioning Data
Divide elements into exactly two boolean groups.
import java.util.*;
import java.util.stream.Collectors;
public class PartitioningDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6);
Map<Boolean,List<Integer>> result = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(result);
}
}{false=[1, 3, 5], true=[2, 4, 6]}Check your understanding: Where are even values placed?
Under the true key.
Step 29 of 30
10.29 Stream Laziness
Demonstrate that intermediate work waits for terminal demand.
numbers.stream().filter(number -> {
System.out.println(number);
return number % 2 == 0;
}); // no outputnumbers.stream()
.filter(number -> { System.out.println(number); return number % 2 == 0; })
.forEach(System.out::println);Check your understanding: Why does a filter-only pipeline print nothing?
No terminal operation requests any elements.
Step 30 of 30
10.30 A Stream Cannot Be Reused
Create a fresh stream after a terminal operation.
Stream<String> stream = names.stream();
stream.forEach(System.out::println);
// stream.count(); // IllegalStateExceptionlong count = names.stream().count();Check your understanding: How should count() be performed after a previous traversal?
Call names.stream() again to create a new stream.