A revision project covering Java 8+ Streams, Lambdas, and Collectors through interview-focused practice questions.
No Spring Boot. No dependencies. Plain Java only. Run
StreamApi.javadirectly from IntelliJ using Java 25 (supportsvoid main()).
Open StreamApi.java in IntelliJ and hit Run.
No build step needed — uses Java 25 unnamed class feature (void main()).
A Stream is a sequence of elements that you can process with a pipeline of operations. It does not store data — it processes it from a source (List, Array, Map etc.).
Source → Intermediate Operations → Terminal Operation
↓ ↓ ↓
List filter, map collect, forEach
sorted, limit reduce, count
A shorthand for writing anonymous functions inline.
// without lambda
list.stream().filter(new Predicate<Integer>() {
public boolean test(Integer n) { return n % 2 == 0; }
});
// with lambda
list.stream().filter(n -> n % 2 == 0);Even shorter than a lambda when you're just calling an existing method.
// lambda
fruits.stream().map(s -> s.toUpperCase());
// method reference
fruits.stream().map(String::toUpperCase);| Operation | What it does | Example |
|---|---|---|
filter |
Keep elements matching condition | .filter(n -> n > 3) |
map |
Transform each element | .map(s -> s.toUpperCase()) |
sorted |
Sort elements | .sorted(Comparator.reverseOrder()) |
distinct |
Remove duplicates | .distinct() |
limit |
Take first N elements | .limit(3) |
skip |
Skip first N elements | .skip(1) |
flatMap |
Flatten nested lists into one stream | .flatMap(e -> e.skills().stream()) |
mapToInt |
Convert to IntStream | .mapToInt(Integer::intValue) |
mapToDouble |
Convert to DoubleStream | .mapToDouble(i -> i) |
| Operation | What it does | Example |
|---|---|---|
forEach |
Iterate over results | .forEach(System.out::println) |
collect |
Gather into collection | .collect(Collectors.toList()) |
count |
Count elements | .count() |
reduce |
Fold elements into one value | .reduce(0, Integer::sum) |
findFirst |
Get first match as Optional | .findFirst() |
min / max |
Get min or max as Optional | .max(Comparator.naturalOrder()) |
anyMatch |
True if any element matches | .anyMatch(n -> n > 5) |
allMatch |
True if all elements match | .allMatch(n -> n > 0) |
noneMatch |
True if no element matches | .noneMatch(n -> n < 0) |
toArray |
Collect into array | .toArray() |
// to List, Set, UnmodifiableList
.collect(Collectors.toList())
.collect(Collectors.toSet())
.collect(Collectors.toUnmodifiableList())
// join strings
.collect(Collectors.joining(","))
// count per group
.collect(Collectors.groupingBy(w -> w, Collectors.counting()))
// group into lists
.collect(Collectors.groupingBy(Employees::department))
// group with downstream — avg, sum, min, max
.collect(Collectors.groupingBy(Employees::department, Collectors.averagingDouble(Employees::salary)))
.collect(Collectors.groupingBy(Employees::department, Collectors.summingInt(Employees::salary)))
.collect(Collectors.groupingBy(Employees::department, Collectors.maxBy(Comparator.comparingInt(Employees::salary))))
// nested grouping
.collect(Collectors.groupingBy(e::department, Collectors.groupingBy(e::gender)))
// split into two groups — true / false
.collect(Collectors.partitioningBy(n -> n % 2 == 0))// sum
int sum = list.stream().reduce(0, Integer::sum);
// product
int product = list.stream().reduce(1, (a, b) -> a * b);
// max without Comparator
Optional<Integer> max = list.stream().reduce(Integer::max);
reducetakes an identity value (starting point) and a BinaryOperator. Without identity it returnsOptionalbecause the stream might be empty.
Returned by findFirst, min, max, reduce (without identity).
Never call .get() directly — use safe alternatives.
Optional<Integer> result = list.stream().filter(n -> n > 4).findFirst();
result.ifPresent(v -> System.out.println(v)); // only runs if value exists
result.orElse(-1); // default if empty
result.orElseThrow(); // throw if empty
result.isPresent(); // boolean checkOne call gives you count, sum, min, max, average all at once.
IntSummaryStatistics stats = list.stream()
.mapToInt(Integer::intValue)
.summaryStatistics();
stats.getCount();
stats.getSum();
stats.getMin();
stats.getMax();
stats.getAverage();// map — one-to-one transformation, stream of lists
employeeSkills.stream()
.map(e -> e.skills()) // Stream<List<String>>
.forEach(System.out::println); // prints each list
// flatMap — flatten, stream of individual elements
employeeSkills.stream()
.flatMap(e -> e.skills().stream()) // Stream<String>
.forEach(System.out::println); // prints each skillUse
flatMapwhenever you have nested lists and want to process individual elements.
// range
IntStream.range(1, 6).forEach(System.out::println); // 1 2 3 4 5
IntStream.rangeClosed(1, 5).forEach(System.out::println); // 1 2 3 4 5
// merge two int arrays
int[] merged = IntStream.concat(Arrays.stream(arr1), Arrays.stream(arr2))
.sorted()
.toArray();
// merge two String/object streams
Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());| # | Question | Key Operations |
|---|---|---|
| 01 | Second largest number | distinct sorted skip limit |
| 02 | All even numbers | filter |
| 06 | Average of list | mapToDouble average |
| 09 | Find duplicates | filter Collections.frequency distinct |
| 10 | Square of first 3 even numbers | sorted filter limit map |
| 11 | Convert strings to uppercase | map method reference |
| 12 | Concatenate list of strings | Collectors.joining |
| 13 | Count strings starting with char | filter count |
| 14 | Remove duplicate words from string | Arrays.stream split distinct |
| 15 | Word frequency in string | groupingBy counting |
| 16 | Group names by first letter + count | groupingBy charAt counting |
| 17 | Merge two int arrays sorted | IntStream.concat sorted toArray |
| 18 | Concat two lists remove duplicates | Stream.concat distinct |
| 19 | Filter palindromes | filter StringBuilder.reverse |
| 20 | Partition even and odd | partitioningBy |
| 21 | Sort employees by id descending | sorted Comparator.comparing |
| 26 | Sort Map by key / value | entrySet comparingByKey comparingByValue |
| 27 | Group employees by department | groupingBy |
| 28 | Average salary per department | groupingBy averagingDouble |
| 29 | Sum salary per department | groupingBy summingInt |
| 30 | Highest/lowest paid per department | groupingBy maxBy minBy |
| 31 | Group by department then gender | nested groupingBy |
| 32 | Group strings by length | groupingBy String::length |
| 33 | Count word occurrences | groupingBy counting |
| 34 | Reverse each word in sentence | map StringBuilder.reverse joining |
| 35 | Unique words across paragraphs | flatMap distinct |
| 36 | Unique skills from employees | flatMap distinct toSet |
| E1 | reduce — sum, product, max | reduce |
| E2 | Collect to Set / UnmodifiableList | toSet toUnmodifiableList |
| E3 | Optional — findFirst, min, max | Optional ifPresent orElse |
| E4 | anyMatch / allMatch / noneMatch | short-circuit terminal ops |
| E5 | summaryStatistics | mapToInt summaryStatistics |
| Mistake | Fix |
|---|---|
Calling .get() on Optional |
Use .orElse() or .ifPresent() |
Using map when you need flatMap |
If result is Stream<List<T>> use flatMap |
reduce without identity returns Optional |
Handle it — don't chain directly |
| Stream already consumed error | Create a new stream — can't reuse |
sorted() on strings is case-sensitive |
Use Comparator.comparing(String::toLowerCase) |