
14. Java Stream API
This section focuses on Java Stream API concepts including functional programming, lazy evaluation, stream operations, Optional, lambda expressions, collectors, parallel streams, and common performance considerations in modern Java applications.
1. What is Stream API?
Stream API is a Java feature introduced in Java 8 for processing collections in a functional and declarative style.
Example:
List<String> names = users.stream()
.map(User::getName)
.filter(name -> name.startsWith("A"))
.toList();Instead of writing manual loops:
for (...) {
}developers can describe:
What should happeninstead of:
How to iterate manuallyA stream represents a sequence of elements supporting operations such as:
Filtering
Mapping
Sorting
Grouping
Aggregation
TransformationStream API improves readability and functional-style programming.
2. Why do we use Stream API?
Stream API helps simplify data processing.
Without streams:
List<String> result = new ArrayList<>();
for (User user : users) {
if (user.isActive()) {
result.add(user.getName());
}
}With streams:
List<String> result = users.stream()
.filter(User::isActive)
.map(User::getName)
.toList();Advantages:
Cleaner code
Less boilerplate
Functional programming style
Easy transformation pipelines
Parallel processing support
Better readabilityStreams are heavily used in modern enterprise Java applications.
3. Difference between Collection and Stream?
This is a common interview question.
Collection | Stream |
|---|---|
Stores data | Processes data |
In-memory structure | Computation pipeline |
Supports direct modification | Does not modify source |
Can iterate multiple times | Usually consumed once |
Collection focuses on:
Data storageStream focuses on:
Data processingExample:
List<String> list;stores elements.
Example:
list.stream()creates processing pipeline.
4. What is lazy evaluation?
Lazy evaluation means stream operations are not executed immediately.
Example:
users.stream()
.filter(u -> {
System.out.println(u.getName());
return true;
});Nothing happens yet.
Execution starts only when a terminal operation appears.
Example:
.count();This allows:
Optimization
Reduced unnecessary work
Efficient pipelinesLazy evaluation is one of the key stream concepts.
5. What is intermediate operation?
Intermediate operations return another stream.
Examples:
map()
filter()
sorted()
distinct()
limit()
skip()Characteristics:
Lazy
Chainable
Do not execute immediatelyExample:
users.stream()
.filter(User::isActive)
.map(User::getName)No actual processing happens yet.
6. What is terminal operation?
Terminal operations trigger stream execution and produce final result.
Examples:
collect()
count()
forEach()
reduce()
findFirst()
toList()Example:
users.stream()
.filter(User::isActive)
.count();count() triggers execution.
After terminal operation, stream cannot be reused.
7. What is map()?
map() transforms elements one-to-one.
Example:
List<String> names = users.stream()
.map(User::getName)
.toList();Transformation:
User → StringEach input element produces exactly one output element.
8. What is filter()?
filter() removes elements that do not match a condition.
Example:
users.stream()
.filter(User::isActive)Only active users remain.
Filtering uses predicates returning:
true
or
false9. What is flatMap()?
flatMap() transforms and flattens nested structures.
Example:
List<List<String>> list;Using flatMap():
List<String> result = list.stream()
.flatMap(Collection::stream)
.toList();Result:
Nested lists become single listVery common for nested collections.
10. Difference between map and flatMap?
map()
One input produces one output.
Example:
User → NameflatMap()
One input may produce multiple outputs which are flattened.
Example:
List<List<String>>
→ List<String>Example:
.map(User::getOrders)Result:
Stream<List<Order>>Example:
.flatMap(user -> user.getOrders().stream())Result:
Stream<Order>11. What is reduce()?
reduce() combines stream elements into a single result.
Example:
int sum = numbers.stream()
.reduce(0, Integer::sum);Flow:
0 + 1 + 2 + 3 ...Used for:
Summation
Aggregation
Combining values
Custom accumulation12. What is collect()?
collect() converts stream results into collections or other structures.
Example:
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());Common collectors:
toList()
toSet()
toMap()
joining()
groupingBy()13. What is groupingBy()?
groupingBy() groups elements based on classification logic.
Example:
Map<String, List<User>> grouped =
users.stream()
.collect(Collectors.groupingBy(User::getDepartment));Result:
Department → UsersVery common in reporting and aggregation.
14. What is partitioningBy()?
partitioningBy() splits elements into two groups using boolean condition.
Example:
Map<Boolean, List<User>> result =
users.stream()
.collect(Collectors.partitioningBy(User::isActive));Result:
true → active users
false → inactive usersUnlike groupingBy, partitioning always produces exactly two groups.
15. What is peek()?
peek() allows inspecting stream elements during processing.
Example:
users.stream()
.peek(System.out::println)Mostly used for:
Debugging
Logging
InspectionImportant:
peek() should not contain business logicbecause streams are intended for functional-style operations.
16. What is distinct()?
distinct() removes duplicate elements.
Example:
numbers.stream()
.distinct()Internally uses:
equals()
hashCode()for uniqueness checks.
17. What is sorted()?
sorted() sorts stream elements.
Example:
users.stream()
.sorted(Comparator.comparing(User::getName))Can use:
Natural ordering
Custom comparators18. What is limit()?
limit(n) restricts number of elements.
Example:
users.stream()
.limit(10)Returns only first 10 elements.
Very useful for:
Pagination
Sampling
Performance optimization19. What is skip()?
skip(n) ignores first N elements.
Example:
users.stream()
.skip(10)Commonly used with pagination.
20. What is Optional?
Optional is a container representing possible absence of value.
Example:
Optional<User>Instead of returning:
nullOptional explicitly models missing value.
21. Why use Optional?
Benefits:
Reduces NullPointerException
Forces explicit null handling
Improves API readability
Encourages safer codeExample:
userRepository.findById(id)
.orElseThrow();Optional makes absence handling explicit.
22. What is orElse()?
orElse() provides default value if Optional is empty.
Example:
String name = optional.orElse("Unknown");If value exists:
Return actual valueOtherwise:
Return default value23. Difference between orElse and orElseGet?
Important interview question.
orElse()
Always evaluates argument.
Example:
optional.orElse(expensiveMethod());expensiveMethod() executes even if Optional contains value.
orElseGet()
Executes supplier lazily.
Example:
optional.orElseGet(() -> expensiveMethod());Method executes only if Optional is empty.
orElseGet() is better for expensive computations.
24. What is ifPresent()?
ifPresent() executes code only if value exists.
Example:
optional.ifPresent(System.out::println);Avoids manual null checking.
25. What is method reference?
Method reference is shorthand lambda syntax.
Example lambda:
user -> user.getName()Method reference equivalent:
User::getNameCleaner and more readable.
26. What is lambda expression?
Lambda provides concise anonymous function syntax.
Example:
x -> x * 2Before Java 8:
new Runnable() {
@Override
public void run() {
}
}With lambda:
() -> System.out.println("Hello")Lambdas simplify functional programming.
27. What is functional interface?
Functional interface contains exactly one abstract method.
Example:
@FunctionalInterface
interface Calculator {
int add(int a, int b);
}Examples in Java:
Runnable
Callable
Function
Consumer
Supplier
PredicateLambdas work with functional interfaces.
28. What is parallel stream?
Parallel streams process data using multiple threads automatically.
Example:
users.parallelStream()
.map(User::getName)
.toList();Internally uses:
ForkJoinPoolBenefits:
Potential performance improvement
Parallel CPU usageEspecially useful for CPU-intensive workloads.
29. When should parallel stream be avoided?
Parallel streams may cause problems for:
Small datasets
IO-heavy tasks
Shared mutable state
Database operations
Blocking operationsProblems include:
Thread contention
Higher overhead
Unpredictable performance
Concurrency bugsParallel streams are not automatically faster.
Always benchmark performance before using them.
30. What are stream performance issues?
Common issues:
Problem | Explanation |
|---|---|
Excessive object creation | Streams create many temporary objects |
Boxing/unboxing overhead | Primitive wrappers reduce performance |
Overusing streams | Complex chains reduce readability |
Parallel stream misuse | Thread overhead may hurt performance |
Repeated stream creation | Unnecessary processing overhead |
Example inefficient code:
list.stream()
.filter(...)
.collect(...)inside tight loops repeatedly.
Streams improve readability, but performance-sensitive systems should still be profiled and benchmarked carefully.
