Java interview questions on streams
Core Concepts
-
What is a Stream?
A sequence of elements that supports sequential or parallel operations. Streams do not store data; they operate on a source (e.g., collection) and support functional-style operations such as filter, map, and reduce. -
Stream vs. Collection
- Collections store data, while streams process it on demand.
- Streams are lazy, meaning operations execute only when a terminal operation is invoked.
-
Intermediate vs. Terminal Operations
- Intermediate operations: filter, map, sorted (return a new stream, lazy).
- Terminal operations: collect, forEach, reduce (produce a result or side effect, eager).
Common Operations
-
Filter vs. Map
- filter(Predicate): Selects elements matching a condition.
- map(Function): Transforms elements into another shape, such as extracting a field.
-
Reduce
Combines elements into a single result, such as the sum of numbers:int sum = numbers.stream().reduce(0, (a, b) -> a + b);
-
FlatMap
Flattens nested collections (e.g., List<List> to List):List<Integer> flatList = nestedList.stream().flatMap(List::stream).toList();
Advanced Concepts
-
Parallel Streams
- Allow processing to occur in multiple threads using parallelStream().
- Thread safety: Ensure the lambda expression is stateless or non-interfering.
-
Stateful vs. Stateless Operations
- Stateless: filter, map (do not depend on other elements).
- Stateful: distinct, sorted (must keep everything in memory).
-
Short-Circuiting Operations
These operations end processing early, such as findFirst, limit, and anyMatch.
Collectors
-
Collectors.toList
Collects the values of a stream into a list:List<String> names = people.stream().map(Person::getName).toList();
-
GroupingBy
Groups elements by a classifier, such as grouping people by age:Map<Integer, List<Person>> peopleByAge = people.stream() .collect(Collectors.groupingBy(Person::getAge));
-
PartitioningBy
Splits elements into two groups (true/false) based on a predicate:Map<Boolean, List<Person>> partitioned = people.stream() .collect(Collectors.partitioningBy(p -> p.getAge() >= 18));
Coding Problems
-
Find distinct elements in a list:
List<Integer> distinct = numbers.stream().distinct().toList();
-
Sum all even numbers:
int sum = numbers.stream().filter(n -> n % 2 == 0).mapToInt(n -> n).sum();
-
Convert a list of strings to uppercase:
List<String> upper = strings.stream().map(String::toUpperCase).toList();
-
Find the longest string in a list:
Optional<String> longest = strings.stream() .max(Comparator.comparingInt(String::length));
-
Concatenate two streams:
Stream<String> combined = Stream.concat(stream1, stream2);
Best Practices & Pitfalls
-
Avoid Side Effects
Stream operations should be stateless; avoid modifying external variables in lambdas. -
Primitive Streams
Performance can be improved using IntStream, LongStream, or DoubleStream for primitive types. -
Reusing Streams
Streams are one-time use only; create new ones if needed. -
ForEach vs. For-Loops
Prefer forEach for clarity, but avoid it for complex mutations or state modifications.
Scenario-Based Interview programming Questions On Java Streams
-
How to handle exceptions in streams?
Wrap checked exceptions in a lambda with try-catch or use utility methods like Unchecked:List<String> result = files.stream().map(file -> { try { return readFile(file); } catch (IOException e) { throw new UncheckedIOException(e); } }).toList();
-
When to use parallel streams?
Use for large volumes of data and CPU-bound tasks but avoid for I/O operations or small datasets. -
Why does peek exist?
Used for debugging/logging intermediate stream states, such as peek(System.out::println).
Advanced Coding Challenges
-
Find the second-largest number in a list:
OptionalInt secondLargest = numbers.stream() .distinct() .sorted() .skip(numbers.size() - 2) .findFirst();
-
Merge two lists of objects into a map (ID → Object):
Map<Integer, Person> idToPerson = people.stream() .collect(Collectors.toMap(Person::getId, Function.identity()));
-
Count occurrences of every word in a list:
Map<String, Long> wordCount = words.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
These questions cover fundamental programming concepts, best practices, and optimization strategies. Senior developers may also focus on parallel stream effectiveness and custom collectors.
No comments