Mastering Java 8 Stream API: Complete Interview Guide with Answers

IND TecH SupporT
0

Mastering Java 8 Stream API: Complete Interview Guide with Answers


What is Java 8 Stream API?

Java 8 introduced the Stream API to process collections of objects in a functional style. It helps to perform operations like filtering, mapping, collecting, etc., in a more readable and concise way.

Streams are not data structures; they don't store elements. They are wrappers around data sources such as collections and arrays that provide a fluent interface for performing operations.

java streams api



How is Stream different from a Collection?

Aspect
Collection
Stream
Stores Data
Yes
No
Iteration Style
External Iteration
Internal Iteration
Reusable
Yes
No (once consumed, can't reuse)
Evaluation
Eager
Lazy (for intermediate ops)

Is a Stream reusable?

No. Once a stream has been consumed using a terminal operation, it can't be reused. A new stream must be created to apply further processing.


Intermediate vs Terminal Operations

  • Intermediate: Return another Stream (e.g., map, filter, sorted)

Operation
Description
filter
Filter elements
map
Transform each element
flatMap
Flatten nested structure
distinct
Remove duplicates
sorted
Sort elements
limit
Take only N elements
skip
Skip first N elements
peek
Look into elements (debug/logging)
mapToInt
Convert to IntStream
mapToLong
Convert to LongStream
mapToDouble
Convert to DoubleStream
takeWhile
Take elements while condition is true
dropWhile
Drop elements while condition is true
    
  • Terminal: Trigger the processing and produce a result or side-effect (e.g., collect, forEach, reduce)

Terminal Operation Description
forEach() Iterate over each element
toArray() Convert stream to array
reduce() Reduce stream to a single value
collect() Collect elements into List, Set, etc.
min() / max() Get smallest/largest element
count() Count elements in the stream
anyMatch() Check if any element matches condition
allMatch() Check if all elements match condition
noneMatch() Check if no elements match condition
findFirst() Get the first element (if present)
findAny() Get any element (non-deterministic)

map() vs flatMap()

  • map() transforms each element of the stream.

  • flatMap() is used to flatten a stream of collections.

List<String> words = Arrays.asList("Hello", "World");
List<String> letters = words.stream()
    .flatMap(word -> Arrays.stream(word.split("")))
    .collect(Collectors.toList());

filter() in Streams

filter() is used to select elements based on a predicate.

List<String> result = list.stream()
    .filter(s -> s.startsWith("A"))
    .collect(Collectors.toList());

Stream Creation Methods

  • stream() from Collection

  • Stream.of(...)

  • Arrays.stream(...)

  • Stream.iterate(...)

  • Stream.generate(...)


Short-circuiting in Streams

Operations like limit(n), findFirst(), anyMatch() stop processing once their condition is met.


Lazy Evaluation

Intermediate operations are not evaluated until a terminal operation is invoked.


collect() to List and Set

List<String> names = stream.collect(Collectors.toList());
Set<String> uniqueNames = stream.collect(Collectors.toSet());

reduce() Explained

Used to combine elements of a stream into a single result.

int sum = numbers.stream().reduce(0, Integer::sum);

Optional in Streams

Used with terminal operations like findFirst(), max(), etc., to handle the case when no result is found.


Sorting with Streams

list.stream().sorted().collect(Collectors.toList());

Grouping

Map<String, List<Employee>> deptMap = employees.stream()
    .collect(Collectors.groupingBy(Employee::getDepartment));

Removing Duplicates

list.stream().distinct().collect(Collectors.toList());

Sequential vs Parallel Streams

  • Sequential: processes elements in order.

  • Parallel: splits the task and processes using multiple threads.

list.parallelStream().forEach(System.out::println);

Debugging with peek()

Used for debugging; allows viewing the stream elements without modifying them.

stream.peek(System.out::println).collect(Collectors.toList());

Interview Coding Examples

  • Second Highest Salary:

Optional<Integer> secondHighest = salaries.stream()
    .distinct()
    .sorted(Comparator.reverseOrder())
    .skip(1)
    .findFirst();

  • Character Frequency:

Map<Character, Long> freq = str.chars()
    .mapToObj(c -> (char)c)
    .collect(Collectors.groupingBy(c -> c, Collectors.counting()));

  •  Sort Transactions:

transactions.stream()
    .filter(t -> t.getYear() == 2022)
    .sorted(Comparator.comparing(Transaction::getAmount))
    .collect(Collectors.toList());

  • Duplicates in List:

Set<String> seen = new HashSet<>();
list.stream()
    .filter(s -> !seen.add(s))
    .collect(Collectors.toSet());

  • List to Uppercase:

list.stream().map(String::toUpperCase).collect(Collectors.toList());

  • Flatten List of Lists:

listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

  •  Max/Min in Stream:

Optional<Integer> max = list.stream().max(Integer::compareTo);

  • Partitioning Even/Odd:

Map<Boolean, List<Integer>> partitioned = numbers.stream()
    .collect(Collectors.partitioningBy(n -> n % 2 == 0));

----------------------------------------------------------------------------------------------------------------------

Java 8 Stream API Interview Questions & Answers 

1. What is Stream in Java 8?

A Stream is a sequence of elements that you can process in a functional style. Think of it like a smart pipeline – it lets you filter, map, sort, and collect data effortlessly without writing loops.


2. Stream vs Collection

  • Collection stores data (like a box of fruits).

  • Stream processes data (like a machine processing fruits).

Collections are data containers, while Streams are views on that data to perform computation.


3. Types of Streams

  • Sequential Stream – Processes elements in order.

  • Parallel Stream – Uses multiple threads for better performance on large data sets.


4. How to create a Stream?

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

You can create streams from collections, arrays, or using Stream.of().


5. filter()

Filters elements based on a condition.

list.stream().filter(s -> s.startsWith("a"));

Only keeps elements that start with "a".


6. map()

Transforms each element.

list.stream().map(String::toUpperCase);

Like converting lowercase letters to uppercase.


7. flatMap()

Flattens nested structures.

listOfLists.stream().flatMap(List::stream);

If you have a list of lists, this combines them into one big stream.


8. distinct()

Removes duplicates.

list.stream().distinct();

Like filtering out repeated values.


9. sorted()

Sorts elements.

list.stream().sorted();

Natural or custom sorting.


10. limit() and skip()

  • limit(n) – Get only first n elements.

  • skip(n) – Skip first n elements.


11. collect()

Terminal operation to convert Stream to List, Set, Map, etc.

List<String> result = list.stream().collect(Collectors.toList());

12. forEach()

Used for side-effects like printing.

list.stream().forEach(System.out::println);

13. reduce()

Reduces the stream to a single value.

int sum = list.stream().reduce(0, Integer::sum);

Like summing numbers or concatenating strings.


14. min(), max(), count()

list.stream().min(Comparator.naturalOrder());

Finds smallest, largest, or total elements.


15. anyMatch(), allMatch(), noneMatch()

Check if some/all/none elements match a condition.

list.stream().anyMatch(s -> s.startsWith("a"));

16. toArray()

Convert Stream to array.

String[] arr = list.stream().toArray(String[]::new);

17. Stream.of()

Creates stream from given values.

Stream.of("a", "b", "c");

18. Generating infinite streams

Stream.iterate(1, n -> n + 1).limit(10);

Useful in special scenarios.


19. How does lazy evaluation work in Streams?

Streams process elements only when needed. Intermediate operations are not executed until a terminal operation is called.


20. Short-circuiting in Streams

Operations like limit(), findFirst() can end processing early.


21. Parallel Stream vs Stream

Parallel stream uses multiple threads and can improve performance – but not always. Use carefully in performance-heavy operations.


22. What are terminal and intermediate operations?

  • Intermediate: filter(), map(), etc. – returns a stream.

  • Terminal: collect(), forEach(), reduce() – ends the stream pipeline.


23. How to debug a Stream pipeline?

Use .peek() to look at the elements.

stream.peek(System.out::println)

24. Can we reuse a Stream?

No. Once a stream is consumed, it cannot be reused.


25. When not to use Streams?

  • If you need indexed access.

  • If debugging is hard.

  • When performance is critical and measured.


26. Real-World Use Case

Processing list of orders, filtering out cancelled ones, mapping to their prices, summing total revenue.

orders.stream()
  .filter(o -> !o.isCancelled())
  .map(Order::getPrice)
  .reduce(0, Integer::sum);


Post a Comment

0Comments

Post a Comment (0)

you may like it