1. What are Intermediate and Terminal Operations in Java Streams?
Answer:
- Intermediate Operations (e.g.,
filter()
,map()
,sorted()
) are lazy and return a new stream. - Terminal Operations (e.g.,
collect()
,forEach()
,reduce()
) trigger processing and produce a result.
Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0) // Intermediate
.map(n -> n * 2) // Intermediate
.collect(Collectors.toList()); // Terminal
// Output: [4, 8]
2. Difference Between filter()
and map()
?
Answer:
filter()
→ Selects elements based on a condition (Predicate
).map()
→ Transforms each element (Function
).
Example:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> lengths = names.stream()
.filter(name -> name.length() > 3) // ["Alice", "Charlie"]
.map(String::length) // [5, 7]
.collect(Collectors.toList());
3. What Does flatMap()
Do?
Answer:
- Flattens nested collections into a single stream.
Example:
List<List<String>> nestedList = Arrays.asList(
Arrays.asList("A", "B"),
Arrays.asList("C", "D")
);
List<String> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
// Output: ["A", "B", "C", "D"]
4. How Does distinct()
Work?
Answer:
- Removes duplicates using
equals()
.
Example:
List<Integer> nums = Arrays.asList(1, 2, 2, 3, 3, 3);
List<Integer> unique = nums.stream()
.distinct()
.collect(Collectors.toList());
// Output: [1, 2, 3]
5. Explain sorted()
with Custom Comparator
Answer:
- Sorts elements (natural order or custom
Comparator
).
Example:
List<String> names = Arrays.asList("Zack", "Anna", "Bob");
List<String> sorted = names.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
// Output: ["Zack", "Bob", "Anna"]
6. What is peek()
Used For?
Answer:
- Debugging intermediate stream operations (does not modify elements).
Example:
List<Integer> nums = Arrays.asList(1, 2, 3);
List<Integer> result = nums.stream()
.peek(n -> System.out.println("Before: " + n))
.map(n -> n * 2)
.peek(n -> System.out.println("After: " + n))
.collect(Collectors.toList());
7. How Does limit()
Work?
Answer:
- Truncates the stream to a given size.
Example:
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> limited = nums.stream()
.limit(3)
.collect(Collectors.toList());
// Output: [1, 2, 3]
8. What is skip()
in Streams?
Answer:
- Skips the first
n
elements.
Example:
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skipped = nums.stream()
.skip(2)
.collect(Collectors.toList());
// Output: [3, 4, 5]
9. Terminal Operation: collect()
vs toList()
(Java 16+)
Answer:
collect(Collectors.toList())
(Java 8)toList()
(Java 16+, returns immutable list)
Example:
List<String> names = Arrays.asList("A", "B", "C");
List<String> list1 = names.stream().collect(Collectors.toList()); // Mutable
List<String> list2 = names.stream().toList(); // Immutable (Java 16+)
10. How Does reduce()
Work?
Answer:
- Combines elements into a single result.
Example:
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
int sum = nums.stream()
.reduce(0, (a, b) -> a + b);
// Output: 10
11. Terminal Operation: forEach()
vs forEachOrdered()
Answer:
forEach()
→ Order not guaranteed in parallel streams.forEachOrdered()
→ Maintains order.
Example:
List<Integer> nums = Arrays.asList(1, 2, 3);
nums.stream().parallel().forEach(System.out::println); // Random order
nums.stream().parallel().forEachOrdered(System.out::println); // 1, 2, 3
12. What is anyMatch()
, allMatch()
, noneMatch()
?
Answer:
anyMatch()
→ At least one element matches.allMatch()
→ All elements match.noneMatch()
→ No elements match.
Example:
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
boolean hasEven = nums.stream().anyMatch(n -> n % 2 == 0); // true
boolean allEven = nums.stream().allMatch(n -> n % 2 == 0); // false
boolean noneNegative = nums.stream().noneMatch(n -> n < 0); // true
13. Terminal Operation: count()
Answer:
- Returns the number of elements.
Example:
long count = Stream.of(1, 2, 3, 4).count(); // 4
14. Terminal Operation: min()
and max()
Answer:
- Finds min/max using a
Comparator
.
Example:
Optional<Integer> min = Stream.of(5, 2, 8).min(Integer::compare); // 2
Optional<Integer> max = Stream.of(5, 2, 8).max(Integer::compare); // 8
15. Terminal Operation: findFirst()
vs findAny()
Answer:
findFirst()
→ First element (order matters).findAny()
→ Any element (faster in parallel).
Example:
Optional<Integer> first = Stream.of(1, 2, 3).findFirst(); // 1
Optional<Integer> any = Stream.of(1, 2, 3).parallel().findAny(); // Random
16. How to Convert Stream to Array?
Answer:
- Using
toArray()
.
Example:
String[] names = Stream.of("A", "B", "C").toArray(String[]::new);
17. Terminal Operation: joining()
Collector
Answer:
- Concatenates strings with optional delimiter.
Example:
String joined = Stream.of("A", "B", "C").collect(Collectors.joining(", "));
// Output: "A, B, C"
18. Terminal Operation: groupingBy()
Collector
Answer:
- Groups elements by a classifier.
Example:
Map<Integer, List<String>> grouped = Stream.of("A", "BB", "CC")
.collect(Collectors.groupingBy(String::length));
// Output: {1=["A"], 2=["BB", "CC"]}
19. Terminal Operation: partitioningBy()
Collector
Answer:
- Splits into
true
/false
partitions.
Example:
Map<Boolean, List<Integer>> partitioned = Stream.of(1, 2, 3, 4)
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
// Output: {false=[1, 3], true=[2, 4]}
20. Terminal Operation: summingInt()
, averagingDouble()
Answer:
- Aggregates numeric values.
Example:
double avg = Stream.of(1, 2, 3)
.collect(Collectors.averagingInt(n -> n)); // 2.0
21. What is Stream.concat()
?
Answer:
- Merges two streams.
Example:
Stream<String> s1 = Stream.of("A", "B");
Stream<String> s2 = Stream.of("C", "D");
Stream<String> merged = Stream.concat(s1, s2);
// Output: ["A", "B", "C", "D"]
22. How to Handle Null
in Streams?
Answer:
- Use
filter(Objects::nonNull)
.
Example:
List<String> names = Arrays.asList("A", null, "B");
List<String> nonNull = names.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
// Output: ["A", "B"]
23. What is Stream.iterate()
?
Answer:
- Generates infinite streams.
Example:
Stream.iterate(0, n -> n + 2)
.limit(5)
.forEach(System.out::println); // 0, 2, 4, 6, 8
24. What is Stream.generate()
?
Answer:
- Creates streams from a
Supplier
.
Example:
Stream.generate(() -> Math.random())
.limit(3)
.forEach(System.out::println); // Random numbers
25. How to Parallelize a Stream?
Answer:
- Use
.parallel()
orparallelStream()
.
Example:
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
int sum = nums.parallelStream()
.reduce(0, Integer::sum);
// Output: 10 (processed in parallel)
Summary Table
Operation | Type | Example |
---|---|---|
filter() | Intermediate | .filter(x -> x > 5) |
map() | Intermediate | .map(String::length) |
flatMap() | Intermediate | .flatMap(List::stream) |
distinct() | Intermediate | .distinct() |
sorted() | Intermediate | .sorted(Comparator.reverseOrder()) |
peek() | Intermediate | .peek(System.out::println) |
limit() | Intermediate | .limit(3) |
skip() | Intermediate | .skip(2) |
collect() | Terminal | .collect(Collectors.toList()) |
reduce() | Terminal | .reduce(0, Integer::sum) |
forEach() | Terminal | .forEach(System.out::println) |
anyMatch() | Terminal | .anyMatch(x -> x > 5) |
Key Takeaways
✅ Intermediate ops (filter
, map
, sorted
) are lazy.
✅ Terminal ops (collect
, reduce
, forEach
) trigger processing.
✅ flatMap()
flattens nested collections.
✅ reduce()
combines elements into a single result.
✅ parallelStream()
improves performance for large datasets.