Java Interview Prep — Session 3
Stream API Coding Practice
Session Score Card
Question Topic Score
Q1 Filter — startsWith digit 8/10
Q2 groupingBy first character 5/10
Q3 Second highest with distinct 7/10
Q4 filter + mapToInt + sum 6/10
Q5 List to Map with toMap 10/10
Q1: Find all numbers starting with digit 1
Input:
List numbers = [Link](1, 12, 23, 100, 145, 56, 13, 200);
Solution:
[Link]() .filter(num -> [Link](num).startsWith("1"))
.collect([Link]()); // Output: [1, 12, 100, 145, 13]
No need for .map() — use [Link]() or [Link]() directly inside filter. startsWith() is more
readable than charAt(0) == '1'.
Q2: Group strings by first character
Input:
List words = [Link]("apple","avocado","banana","blueberry","cherry");
Solution:
Map> map = [Link]() .collect([Link](word -> [Link](0))); //
Output: {a=[apple, avocado], b=[banana, blueberry], c=[cherry]}
INTERVIEW TRAP: Use groupingBy when multiple values share same key. Use toMap when each key maps
to exactly ONE value. Mixing these up is the most common Stream mistake.
Q3: Find second highest number
Input:
List numbers = [Link](5, 1, 8, 3, 9, 2, 9);
Solution:
int secondHighest = [Link]() .distinct() // remove duplicates: [9,8,5,3,2,1]
.sorted([Link]()) // sort descending .skip(1) // skip highest (9)
.findFirst() // get 8 as Optional .orElseThrow(() -> new RuntimeException("Not enough
elements")); // Output: 8
INTERVIEW TRAP 1: Without .distinct(), skip(1) on [9,9,8,...] lands on second 9, not 8. INTERVIEW TRAP 2:
findFirst() returns Optional — always handle with orElseThrow() or orElse(). Never call .get() directly.
Q4: Sum of salaries by department
Input:
List employees = [Link]( new Employee("Alice", "Engineering", 90000), new
Employee("Bob", "Marketing", 60000), new Employee("Charlie", "Engineering", 85000) );
Solution:
int totalSalary = [Link]() .filter(emp ->
"Engineering".equals([Link]())) .mapToInt(Employee::getSalary) .sum(); //
Output: 175000
INTERVIEW TRAP: .sum() does not exist on Stream. Must convert to primitive stream first using mapToInt(),
mapToDouble(), or mapToLong() before calling sum().
Null safety: Always write "Engineering".equals([Link]()) not
[Link]().equals("Engineering") — prevents NullPointerException if getDepartment() returns null.
Q5: Convert List to Map (name -> salary)
Solution:
Map map = [Link]() .collect([Link]( Employee::getName, // key
Employee::getSalary // value )); // Output: {Alice=90000, Bob=60000, Charlie=85000}
INTERVIEW TRAP: If two employees have the same name, toMap throws IllegalStateException: Duplicate
key. Fix — provide merge function as 3rd argument: [Link](Employee::getName,
Employee::getSalary, (existing, replacement) -> existing)
Stream Terminal Operations — Know These Cold
Operation Use Case Returns
collect(toList()) Gather results into list List<T>
collect(groupingBy(...)) Group by key — multiple values per key Map<K, List<T>>
collect(toMap(...)) One value per key Map<K, V>
mapToInt().sum() Sum integers int
mapToDouble().average() Average of doubles OptionalDouble
findFirst() First matching element Optional<T>
count() Count elements long
anyMatch() Any element matches predicate boolean
allMatch() All elements match predicate boolean
distinct() Remove duplicates Stream<T>
sorted(Comparator) Sort with comparator Stream<T>
skip(n) Skip first n elements Stream<T>
Top Stream API Interview Traps
1. groupingBy vs toMap — groupingBy for multiple values per key, toMap for one-to-one mapping.
2. mapToInt().sum() — can't call sum() on Stream, must convert to primitive stream first.
3. distinct() before sorted() for second highest — otherwise duplicates affect the result.
4. findFirst() returns Optional — always use orElseThrow() or orElse(), never raw .get().
5. toMap duplicate key — always provide merge function as 3rd argument in production.
6. Null safety — put string literal first in equals() check to avoid NullPointerException.
7. Method references (Employee::getName) vs lambdas (emp -> [Link]()) — both valid, method
refs cleaner.
Next: Full Mock Interview Simulation