DevNotes
Support
Java 8 & Streams · Chapter 11

Real Stream Interview Problems

From APIs to problem solving — duplicates, frequencies, first non-repeating element, Nth highest, longest string, per-department analytics and anagrams.

◷ 7 min read§ 9 sections? 5 interview questions{ } 17 code examples

#Introduction

From here on we stop learning APIs and start problem solving — exactly how 5–8 year Java interviews are conducted. The interviewer doesn't ask "What is map()?" Instead they ask:

  • "Given this employee list, find the second highest salary."
  • "Group employees by department and return the highest-paid employee."
  • "Find duplicate characters in a string."

The goal of this chapter is to solve these problems while understanding why a particular Stream solution is the right choice.

#The Problem-Solving Framework

Before writing any code, ask yourself:

  1. Do I need to filter?
  2. Do I need to transform?
  3. Do I need to group?
  4. Do I need to sort?
  5. Do I need a single value?
  6. Do I need a collection?

If you answer these mentally first, the Stream pipeline almost writes itself.

#Number Problems

Problem 1 — Find Duplicate Numbers

Java
List<Integer> list = Arrays.asList(2, 3, 5, 2, 6, 3, 8, 5);

Solution (interview favourite):

Java
Set<Integer> seen = new HashSet<>();

list.stream()
    .filter(n -> !seen.add(n))
    .forEach(System.out::println);
Output
2
3
5

Why does this work? Remember what Set.add() returns:

Java
seen.add(2);   // true  (first time)
seen.add(2);   // false (already exists)

Therefore !seen.add(n) means "keep only duplicates."

Follow-up — why not use distinct()? Because distinct() returns unique elements. We need the opposite.

Problem 2 — Remove Duplicate Numbers

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

Simple.

Problem 3 — Frequency of Numbers

Java
Map<Integer, Long> frequency = list.stream()
        .collect(Collectors.groupingBy(
                Function.identity(),
                Collectors.counting()
        ));
Output
{2=2, 3=2, 5=2, 6=1, 8=1}

Why Function.identity()? Instead of n -> n, you can write Function.identity().

Problem 4 — First Non-Repeating Number

Input 2, 3, 2, 5, 6, 5, 7 → expected 3.

Java
Integer result = list.stream()
        .collect(Collectors.groupingBy(
                Function.identity(),
                LinkedHashMap::new,
                Collectors.counting()
        ))
        .entrySet()
        .stream()
        .filter(e -> e.getValue() == 1)
        .map(Map.Entry::getKey)
        .findFirst()
        .orElse(null);

Why LinkedHashMap? Very important. A normal HashMap does not preserve insertion order. We need 2, 3, 5, 6, 7 to stay in encounter order so that findFirst() really returns the first non-repeating number.

Problem 8 — Second Highest Number

Java
int second = list.stream()
        .distinct()
        .sorted(Comparator.reverseOrder())
        .skip(1)
        .findFirst()
        .orElseThrow();
distinct()
sorted(desc)
skip(1)
findFirst()

Problem 9 — Nth Highest Number

Suppose the 4th highest:

Java
int n = 4;

int result = list.stream()
        .distinct()
        .sorted(Comparator.reverseOrder())
        .skip(n - 1)
        .findFirst()
        .orElseThrow();

Very elegant.

#String Problems

Problem 5 — Character Frequency

Java
Map<Character, Long> result = "programming"
        .chars()
        .mapToObj(c -> (char) c)
        .collect(Collectors.groupingBy(
                Function.identity(),
                Collectors.counting()
        ));
Output
{p=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1}

(The order of a HashMap isn't guaranteed — use LinkedHashMap::new as the map factory if you need encounter order.)

Why chars()? A String is not a collection. chars() converts it into an IntStream, then mapToObj(c -> (char) c) creates a Stream<Character>.

Problem 6 — Duplicate Characters

Java
"programming"
        .chars()
        .mapToObj(c -> (char) c)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet()
        .stream()
        .filter(e -> e.getValue() > 1)
        .forEach(System.out::println);
Output
r=2
g=2
m=2

Problem 7 — First Non-Repeating Character

The most asked Stream interview question. Input programming → expected p.

Java
Character ch = "programming"
        .chars()
        .mapToObj(c -> (char) c)
        .collect(Collectors.groupingBy(
                Function.identity(),
                LinkedHashMap::new,
                Collectors.counting()
        ))
        .entrySet()
        .stream()
        .filter(e -> e.getValue() == 1)
        .map(Map.Entry::getKey)
        .findFirst()
        .orElse(null);
"programming"
Stream<Character>
p=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1
p

Problem 10 — Longest String

Java
List<String> names = Arrays.asList("John", "Alexander", "Bob");

String longest = names.stream()
        .max(Comparator.comparingInt(String::length))
        .orElse("");

Notice: no sorting. Much faster.

Problem 15 — Group Anagrams

Input eat, tea, tan, ate, nat, bat:

Java
Map<String, List<String>> result = words.stream()
        .collect(Collectors.groupingBy(word -> {
            char[] chars = word.toCharArray();
            Arrays.sort(chars);
            return new String(chars);
        }));
aet
eatteaate
ant
tannat
abt
bat
Key = the word's sorted letters

#Employee Problems

Problem 11 — Highest Salary Employee

Java
Employee highest = employees.stream()
        .max(Comparator.comparing(Employee::getSalary))
        .orElseThrow();

Problem 12 — Highest Salary in Each Department

Java
Map<String, Optional<Employee>> result = employees.stream()
        .collect(Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.maxBy(Comparator.comparing(Employee::getSalary))
        ));

Classic interview problem.

Problem 13 — Count Employees Per Department

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

Problem 14 — Average Salary Per Department

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

#Quick-Fire Interview Round

Q1Difference between max() and sorted().findFirst()?

max() is O(n); sorted() is O(n log n). Prefer max().

Q2Why use LinkedHashMap for the first non-repeating character?

Because it preserves insertion order.

Q3Why Function.identity()?

It's equivalent to x -> x.

Q4How do you find duplicates?

filter(n -> !set.add(n)), or group with counting() and keep entries with count > 1.

Q5How do you find the second highest salary?

distinct() → sorted(desc) → skip(1) → findFirst().

#Homework — Top 20 Interview Problems

Using Streams, solve:

  1. First repeating character.
  2. Last repeating character.
  3. Last non-repeating character.
  4. Most frequent character.
  5. Least frequent character.
  6. Reverse each word in a sentence.
  7. Sort words by length.
  8. Top 3 longest words.
  9. Count vowels.
  10. Count consonants.
  11. Employees older than 30 grouped by department.
  12. Department with the highest average salary.
  13. Youngest employee in each department.
  14. Employee names in uppercase grouped by department.
  15. Remove duplicate words from a sentence.
  16. Most expensive product.
  17. Top 5 salaries.
  18. Second youngest employee.
  19. Third highest unique salary.
  20. Employees whose names contain only unique characters.

#Pattern Recognition

Knowing Stream methods is one thing. Being able to look at a problem and immediately think "this is a groupingBy + mapping + maxBy problem" is what distinguishes senior Java developers from developers who have memorized the API. That intuition is the skill that consistently helps in interviews.

#Chapter Summary

  • The six-question problem-solving framework
  • Duplicates with !seen.add(n) (and its parallel-safety caveat)
  • Frequency maps with groupingBy(identity(), counting())
  • First non-repeating element with LinkedHashMap
  • Nth highest with distinct → sorted(desc) → skip(n-1)
  • max() over sorted().findFirst()
  • Group anagrams by sorted key