Skip to content

Stream API Coding Problems

Modern Java functional programming with Stream API - filter, map, reduce, and complex stream operations.


1. Convert a list of strings to uppercase and sort them

View Solution

Problem

Given a list of words, convert all to uppercase and return sorted. Handle case-insensitive sorting.

Approach 1: Stream API (Recommended)

List<String> words = Arrays.asList("banana", "apple", "Cherry", "date");

// Convert to uppercase, sort, and collect
List<String> result = words.stream()
    .map(String::toUpperCase)
    .sorted()
    .collect(Collectors.toList());

System.out.println(result);  // [APPLE, BANANA, CHERRY, DATE]

Approach 2: Case-Insensitive Sort

List<String> result = words.stream()
    .map(String::toUpperCase)
    .sorted(String::compareToIgnoreCase)  // Case-insensitive
    .collect(Collectors.toList());

// Or with explicit comparator
List<String> result = words.stream()
    .map(String::toUpperCase)
    .sorted(Comparator.comparing(String::toString, String.CASE_INSENSITIVE_ORDER))
    .collect(Collectors.toList());

Approach 3: With Duplicates Removal

List<String> result = words.stream()
    .map(String::toUpperCase)
    .distinct()  // Remove duplicates
    .sorted()
    .collect(Collectors.toList());

Complexity Comparison

ApproachTimeSpaceUse Case
Stream map + sortO(n log n)O(n)Simple, clean code
Stream + distinct + sortO(n log n)O(n)Remove duplicates first
Traditional loopO(n log n)O(n)When stream unavailable

πŸ“š Learn more: Stream API & Collections


2. Filter a list of integers and collect even numbers greater than 10

View Solution

Problem

Given a list of integers, filter for even numbers greater than 10, and return as a list.

Approach 1: Stream Filter (Recommended)

List<Integer> numbers = Arrays.asList(5, 12, 8, 15, 20, 3, 18, 7, 25);

// Filter even numbers > 10
List<Integer> result = numbers.stream()
    .filter(n -> n > 10)           // Greater than 10
    .filter(n -> n % 2 == 0)       // Even numbers
    .collect(Collectors.toList());

System.out.println(result);  // [12, 20, 18]

Approach 2: Combined Filter Condition

List<Integer> result = numbers.stream()
    .filter(n -> n > 10 && n % 2 == 0)  // Single filter
    .collect(Collectors.toList());

Approach 3: Filter to Set (Remove Duplicates)

Set<Integer> result = numbers.stream()
    .filter(n -> n > 10 && n % 2 == 0)
    .collect(Collectors.toSet());

Approach 4: Sorted and Limited

List<Integer> result = numbers.stream()
    .filter(n -> n > 10 && n % 2 == 0)
    .sorted(Comparator.reverseOrder())  // Descending
    .limit(2)                            // Top 2
    .collect(Collectors.toList());

// Result: [20, 18]

Complexity Comparison

ApproachTimeSpaceBest For
Two filtersO(n)O(k)Readability
Combined filterO(n)O(k)Performance
Filter to SetO(n)O(k)Uniqueness
Filter + sort + limitO(n log n)O(k)Top-K results

πŸ“š Learn more: Stream API & Collections


3. Use Stream to count occurrences of each string in a list

View Solution

Problem

Given a list of words, count how many times each word appears and return a map of word→count.

Approach 1: groupingBy with Counting (Recommended)

List<String> words = Arrays.asList("apple", "banana", "apple", "cherry", "banana", "apple");

// Group by word and count
Map<String, Long> wordCount = words.stream()
    .collect(Collectors.groupingBy(
        w -> w,                           // Group by word itself
        Collectors.counting()              // Count occurrences
    ));

System.out.println(wordCount);
// {apple=3, banana=2, cherry=1}

Approach 2: Case-Insensitive Counting

Map<String, Long> wordCount = words.stream()
    .map(String::toLowerCase)  // Normalize
    .collect(Collectors.groupingBy(
        w -> w,
        Collectors.counting()
    ));

// "Apple" and "apple" counted together

Approach 3: Sort by Count (Descending)

Map<String, Long> wordCount = words.stream()
    .collect(Collectors.groupingBy(
        w -> w,
        Collectors.counting()
    ));

// Sort by count descending
List<Map.Entry<String, Long>> sorted = wordCount.entrySet()
    .stream()
    .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
    .collect(Collectors.toList());

// or using comparingByValue
List<Map.Entry<String, Long>> sorted = wordCount.entrySet()
    .stream()
    .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
    .collect(Collectors.toList());

sorted.forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
// apple: 3
// banana: 2
// cherry: 1

Approach 4: Traditional HashMap (for comparison)

Map<String, Integer> wordCount = new HashMap<>();
for (String word : words) {
    wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}

Complexity Comparison

ApproachTimeSpaceBest For
groupingBy().counting()O(n)O(k)Clean, functional
HashMap loopO(n)O(k)Performance critical
groupingBy + sortO(n + k log k)O(k)Need sorted results

πŸ“š Learn more: Stream API & Collections


4. Use Stream reduce() to calculate sum, product, and concatenation

View Solution

Problem

Use Stream.reduce() to compute sum, product, and string concatenation of collection elements.

Approach 1: Sum with reduce()

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Sum using reduce
int sum = numbers.stream()
    .reduce(0, Integer::sum);  // 0 is identity/initial value

System.out.println(sum);  // 15

// Or equivalent
int sum = numbers.stream()
    .reduce(0, (a, b) -> a + b);

Approach 2: Product with reduce()

int product = numbers.stream()
    .reduce(1, (a, b) -> a * b);  // 1 is identity for multiplication

System.out.println(product);  // 120 (1*2*3*4*5)

Approach 3: String Concatenation

List<String> words = Arrays.asList("Hello", " ", "World");

// Concatenate strings
String result = words.stream()
    .reduce("", String::concat);  // "" is identity for strings

System.out.println(result);  // "Hello World"

// Or with custom separator
String result = words.stream()
    .reduce((a, b) -> a + "-" + b)
    .orElse("");  // Handle empty stream

System.out.println(result);  // "Hello- -World"

Approach 4: Optional reduce (no identity)

Optional<Integer> sum = numbers.stream()
    .reduce((a, b) -> a + b);  // No identity value

if (sum.isPresent()) {
    System.out.println(sum.get());  // 15
} else {
    System.out.println("Empty stream");
}

// Shorthand
numbers.stream()
    .reduce((a, b) -> a + b)
    .ifPresent(System.out::println);

Approach 5: Complex Reduction - Find Max

Optional<Integer> max = numbers.stream()
    .reduce((a, b) -> a > b ? a : b);

System.out.println(max.get());  // 5

// Equivalent but clearer
Optional<Integer> max = numbers.stream()
    .max(Integer::compare);

Approach 6: Collect vs Reduce

// DON'T: Inefficient string concat with reduce
String result = words.stream()
    .reduce("", (a, b) -> a + b);  // Creates many intermediate strings ❌

// DO: Use Collectors.joining (optimized)
String result = words.stream()
    .collect(Collectors.joining(""));  // βœ… Uses StringBuilder internally

reduce() Summary Table

FunctionIdentityExampleResult
Sum0reduce(0, Integer::sum)15
Product1reduce(1, (a,b) β†’ a*b)120
MaxN/Areduce((a,b) β†’ max(a,b))5
Concat""reduce("", String::concat)"12345"

πŸ“š Learn more: Stream API & Collections


5. Combine multiple Stream operations: filter, map, and collect

View Solution

Problem

Given a list of employees with salary, filter by salary > 50k, extract names, and collect as comma-separated string.

Approach 1: Chained Stream Operations (Recommended)

class Employee {
    String name;
    double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() { return name; }
    public double getSalary() { return salary; }
}

List<Employee> employees = Arrays.asList(
    new Employee("Alice", 75000),
    new Employee("Bob", 45000),
    new Employee("Charlie", 95000),
    new Employee("Diana", 55000),
    new Employee("Eve", 40000)
);

// Filter salary > 50k, map to names, collect as CSV
String result = employees.stream()
    .filter(e -> e.getSalary() > 50000)      // Filter
    .map(Employee::getName)                  // Transform
    .collect(Collectors.joining(", "));      // Collect as string

System.out.println(result);  // "Alice, Charlie, Diana"

Approach 2: Collect to List First

List<String> highEarners = employees.stream()
    .filter(e -> e.getSalary() > 50000)
    .map(Employee::getName)
    .collect(Collectors.toList());

System.out.println(highEarners);  // [Alice, Charlie, Diana]

Approach 3: Multiple Filters

String result = employees.stream()
    .filter(e -> e.getSalary() > 50000)  // Salary filter
    .filter(e -> e.getName().length() > 3)  // Name length filter
    .map(Employee::getName)
    .collect(Collectors.joining(", "));

// Result: "Alice, Charlie, Diana"

Approach 4: Map to Different Object

class EmployeeDTO {
    String name;
    double salary;

    public EmployeeDTO(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
}

List<EmployeeDTO> dtos = employees.stream()
    .filter(e -> e.getSalary() > 50000)
    .map(e -> new EmployeeDTO(e.getName(), e.getSalary()))
    .collect(Collectors.toList());

Approach 5: Sorted Collection

String result = employees.stream()
    .filter(e -> e.getSalary() > 50000)
    .sorted((e1, e2) -> Double.compare(e2.getSalary(), e1.getSalary()))  // Descending
    .map(Employee::getName)
    .collect(Collectors.joining(", "));

// Result: "Charlie, Alice, Diana" (sorted by salary desc)

Approach 6: Group and Collect

Map<Boolean, List<Employee>> grouped = employees.stream()
    .collect(Collectors.partitioningBy(e -> e.getSalary() > 50000));

List<Employee> highEarners = grouped.get(true);
List<Employee> lowEarners = grouped.get(false);

System.out.println("High: " + highEarners.size());  // 3
System.out.println("Low: " + lowEarners.size());    // 2

Stream Pipeline Performance

OperationTypeLazy?Impact
filter()Intermediateβœ… YesProcesses only needed elements
map()Intermediateβœ… YesTransforms elements
sorted()Intermediate❌ NoMust consume entire stream
distinct()Intermediate❌ NoRequires buffering
collect()TerminalN/ATriggers execution

πŸ“š Learn more: Stream API & Collections


See also: Collections Framework, Interview Questions Overview