Tuesday, 18 August 2026

Java Streams - Quick Reference for Interviews


🚀 Java Streams & Functional Programming — Interview Prep

1. Lambda Expression — Foundation

Traditional:

List<String> names = Arrays.asList("Ramesh", "John", "David");

for (String name : names) {
    System.out.println(name);
}

Functional:

names.forEach(name -> System.out.println(name));

Even simpler:

names.forEach(System.out::println);

Interview question

What is a lambda?

A lambda is an anonymous function that allows us to pass behavior as a value.

(a, b) -> a + b

2. Functional Interface

A functional interface contains exactly one abstract method.

@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

Usage:

Calculator addition = (a, b) -> a + b;

System.out.println(addition.calculate(10, 20));

Output:

30

Important built-in functional interfaces:

InterfaceMethodExample
Predicate<T>test()filtering
Function<T,R>apply()transformation
Consumer<T>accept()processing
Supplier<T>get()supplying
UnaryOperator<T>apply()T → T
BinaryOperator<T>apply()T,T → T

3. Predicate — Filtering

Predicate<Integer> isEven = n -> n % 2 == 0;

System.out.println(isEven.test(10));

Output:

true

Stream example:

List<Integer> numbers = List.of(10, 15, 20, 25, 30);

List<Integer> result = numbers.stream()
        .filter(n -> n % 2 == 0)
        .toList();

System.out.println(result);

Output:

[10, 20, 30]

Interview phrase

filter() uses a Predicate because it evaluates a condition and returns true or false.


4. map() — Most Important

Suppose:

List<String> names =
        List.of("ramesh", "john", "david");

Convert to uppercase:

List<String> result = names.stream()
        .map(String::toUpperCase)
        .toList();

Result:

[RAMESH, JOHN, DAVID]

Think:

Input
  ↓
map()
  ↓
Transformation
  ↓
Output

Another example

List<Integer> numbers = List.of(1, 2, 3, 4);

List<Integer> squares = numbers.stream()
        .map(n -> n * n)
        .toList();

Result:

[1, 4, 9, 16]

5. filter() + map()

Very common interview question.

Find squares of even numbers.

List<Integer> result = List.of(1, 2, 3, 4, 5, 6)
        .stream()
        .filter(n -> n % 2 == 0)
        .map(n -> n * n)
        .toList();

Result:

[4, 16, 36]

Pipeline:

1 2 3 4 5 6
      ↓
    filter
      ↓
   2 4 6
      ↓
     map
      ↓
   4 16 36

6. reduce() — Very Important

Find sum:

int sum = List.of(10, 20, 30, 40)
        .stream()
        .reduce(0, Integer::sum);

Result:

100

Conceptually:

0 + 10 + 20 + 30 + 40

Another example:

int max = List.of(10, 50, 20, 80, 30)
        .stream()
        .reduce(Integer.MIN_VALUE, Integer::max);

Result:

80

Interview question

Difference between map() and reduce()?

map() transforms each element.

reduce() combines multiple elements into a single result.


7. sorted()

List<Integer> result = List.of(50, 10, 30, 20)
        .stream()
        .sorted()
        .toList();

Output:

[10, 20, 30, 50]

Descending:

List<Integer> result = numbers.stream()
        .sorted(Comparator.reverseOrder())
        .toList();

8. distinct()

List<Integer> numbers =
        List.of(10, 20, 10, 30, 20, 40);

List<Integer> result = numbers.stream()
        .distinct()
        .toList();

Output:

[10, 20, 30, 40]

9. limit() and skip()

List<Integer> result = numbers.stream()
        .skip(2)
        .limit(3)
        .toList();

Very useful for pagination-like processing, although for database-backed pagination you should generally paginate at the database/query level rather than loading everything into memory first.


10. anyMatch / allMatch / noneMatch

boolean result = numbers.stream()
        .anyMatch(n -> n > 100);

Other examples:

numbers.stream()
       .allMatch(n -> n > 0);
numbers.stream()
       .noneMatch(n -> n < 0);

Interview tip

These are short-circuiting terminal operations.

The stream may stop processing as soon as the answer is known.


11. findFirst() / findAny()

Optional<Integer> result = numbers.stream()
        .filter(n -> n > 50)
        .findFirst();

Always remember:

Optional<T>

rather than assuming a value exists.


12. flatMap() ⭐⭐⭐

This is a very common senior-level interview question.

Suppose:

List<List<Integer>> numbers = List.of(
        List.of(1, 2, 3),
        List.of(4, 5),
        List.of(6, 7)
);

We want:

1 2 3 4 5 6 7

Use:

List<Integer> result = numbers.stream()
        .flatMap(List::stream)
        .toList();

map() vs flatMap()

map():

List<List<Integer>>
        ↓
List<Stream<Integer>>

flatMap():

List<List<Integer>>
        ↓
List<Integer>

Real-world example

List<Employee> employees;

Each employee has:

List<String> skills;

Get all unique skills:

List<String> skills = employees.stream()
        .flatMap(e -> e.getSkills().stream())
        .distinct()
        .sorted()
        .toList();

This is a great interview example.


13. Collectors.groupingBy() ⭐⭐⭐

Suppose:

class Employee {
    String name;
    String department;
    double salary;
}

Group employees by department:

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

Result conceptually:

IT       → [Ramesh, John]
Finance  → [David, Peter]
HR       → [Sita]

Count employees by department

Map<String, Long> countByDept =
        employees.stream()
                .collect(Collectors.groupingBy(
                        Employee::getDepartment,
                        Collectors.counting()
                ));

14. Grouping + Summing

Total salary by department:

Map<String, Double> salaryByDept =
        employees.stream()
                .collect(Collectors.groupingBy(
                        Employee::getDepartment,
                        Collectors.summingDouble(
                                Employee::getSalary
                        )
                ));

This is a very good Java 8 interview problem.


15. PartitioningBy()

Unlike grouping, partitioning creates two groups based on true/false.

Example:

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

Conceptually:

true  → even numbers
false → odd numbers

16. Find Highest Salary

Optional<Employee> employee =
        employees.stream()
                .max(Comparator.comparing(
                        Employee::getSalary
                ));

Safely:

employee.ifPresent(e ->
        System.out.println(e.getName()));

17. Second Highest Salary ⭐⭐⭐

Classic interview question.

Optional<Double> secondHighest =
        employees.stream()
                .map(Employee::getSalary)
                .distinct()
                .sorted(Comparator.reverseOrder())
                .skip(1)
                .findFirst();

Pipeline:

Employees
   ↓
Salary
   ↓
Distinct
   ↓
Descending sort
   ↓
Skip highest
   ↓
Second highest

18. Convert List → Map

Map<Long, Employee> employeeMap =
        employees.stream()
                .collect(Collectors.toMap(
                        Employee::getId,
                        Function.identity()
                ));

Duplicate keys

Important interview trap.

This can fail:

Collectors.toMap(
    Employee::getDepartment,
    Function.identity()
)

if multiple employees have the same department.

Handle it:

Collectors.toMap(
    Employee::getDepartment,
    Function.identity(),
    (e1, e2) -> e1
)

19. String Frequency — Classic Coding Question

String input = "banana";

Map<Character, Long> frequency =
        input.chars()
                .mapToObj(c -> (char) c)
                .collect(Collectors.groupingBy(
                        Function.identity(),
                        Collectors.counting()
                ));

Result:

b → 1
a → 3
n → 2

20. Remove Duplicate Characters

String result = "programming"
        .chars()
        .mapToObj(c -> String.valueOf((char) c))
        .distinct()
        .collect(Collectors.joining());

21. Functional Composition ⭐⭐⭐

Suppose:

Function<Integer, Integer> multiplyBy2 =
        n -> n * 2;

Function<Integer, Integer> add10 =
        n -> n + 10;

Compose:

Function<Integer, Integer> result =
        multiplyBy2.andThen(add10);
System.out.println(result.apply(5));

Output:

20

Because:

5 × 2 = 10
10 + 10 = 20

22. Method References

Instead of:

names.forEach(name -> System.out.println(name));

Use:

names.forEach(System.out::println);

Types:

String::toUpperCase
Employee::getName
System.out::println
Integer::sum

23. Stream Pipeline — Interview Concept ⭐⭐⭐⭐⭐

Remember:

SOURCE
  ↓
INTERMEDIATE OPERATIONS
  ↓
TERMINAL OPERATION

Example:

employees.stream()                 // Source
        .filter(e -> e.getSalary() > 100000)  // Intermediate
        .map(Employee::getName)              // Intermediate
        .sorted()                            // Intermediate
        .toList();                           // Terminal

Important

Intermediate operations are generally lazy.

Nothing actually happens until a terminal operation triggers evaluation.


24. Streams Are Not Collections

Excellent interview question:

Is Stream a data structure?

No.

A Collection stores data.

A Stream represents a pipeline for processing data.

Collection
   ↓
Stream
   ↓
Processing
   ↓
Result

A stream normally doesn't modify the original collection.


25. Parallel Stream — Architect-Level Question ⭐⭐⭐⭐⭐

numbers.parallelStream()
       .map(...)
       .toList();

Don't say:

"Parallel stream is always faster."

That's wrong.

Parallel streams use the ForkJoinPool/common pool by default and introduce overhead.

Good candidates for parallelism:

  • CPU-intensive operations

  • Large datasets

  • Independent operations

Poor candidates:

  • Small collections

  • Blocking I/O

  • DB calls

  • Network calls

  • Operations with shared mutable state

Dangerous

List<Integer> result = new ArrayList<>();

numbers.parallelStream()
       .forEach(result::add);

This introduces unsafe shared mutation.

Prefer:

List<Integer> result =
        numbers.parallelStream()
               .map(...)
               .toList();

🧠 10 Questions You Should Practice Before Monday

  1. map vs flatMap?

  2. map vs filter?

  3. Intermediate vs terminal operations?

  4. Why are Streams lazy?

  5. Can a Stream be reused?

  6. Stream vs Collection?

  7. Sequential vs parallel Stream?

  8. How does groupingBy() work?

  9. How do you handle duplicate keys in toMap()?

  10. Why should we avoid side effects in Streams?

⭐ Senior Architect answer

If asked "What is the biggest advantage of functional programming?", don't just say "less code."

Say:

Functional programming encourages declarative, composable and side-effect-minimized code. This makes transformations easier to reason about, test and compose, and can make parallel processing safer when operations are stateless and independent.

That sounds much more Senior Architect level than simply explaining filter() and map().

No comments:

Post a Comment