Back to Stream: reduce & Aggregate
Q8Question 8 of 9

Concatenate all employee names into a single string separated by ", " using reduce()

Key Concepts
  • The fold identity is an empty string; the accumulator appends each name with a comma separator
  • Guard against a leading comma by checking if the running string is empty before adding the separator
  • The combiner for parallel execution must also join two partial strings with the separator
  • String concatenation in reduce is O(n^2) because each + creates a new String object
  • Collectors.joining uses a StringBuilder internally and is O(n): the production-grade alternative
  • The reduce approach demonstrates folding mechanics; joining is what you use in real code

Definition

reduce from an empty string and append each name, inserting a comma only when the running string is not empty.
  • Identity: empty string "", the starting accumulator and the empty-stream result.
  • Accumulator: if running string is empty, just the name; otherwise running + ", " + name.
  • Combiner: joins two partial strings for parallel execution with the same separator logic.
  • O(n^2): string concatenation in reduce copies all previous characters each time.
  • Production alternative: Collectors.joining(", ") uses StringBuilder for O(n) performance.

Priya is writing one line listing everyone on the team: "Rajesh, Priya, Amit". She starts with an empty line, adds the first name, and for each later name adds a comma-space then the name.

Understanding the Concepts

How do you concatenate names with reduce?

JAVA
package com.bank.hr;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

public class ReduceConcat {
    public static void main(String[] args) {
        List<Employee> staff = List.of(
            new Employee("Rajesh",  "Loans",   new BigDecimal("95000")),
            new Employee("Priya",   "IT",      new BigDecimal("120000")),
            new Employee("Amit",    "Finance", new BigDecimal("85000")));

        String names = staff.stream()
            .map(Employee::getName)
            .reduce("", (a, b) -> a.isEmpty() ? b : a + ", " + b);

        System.out.println(names);
    }
}
TEXT
Rajesh, Priya, Amit

How does the fold work step by step?

| Step | Running string | Next name | Result |
|---|---|---|---|
| Start | "" | - | "" |
| 1 | "" | "Rajesh" | "Rajesh" (empty check) |
| 2 | "Rajesh" | "Priya" | "Rajesh, Priya" |
| 3 | "Rajesh, Priya" | "Amit" | "Rajesh, Priya, Amit" |

What is the combiner for?

The combiner merges two partial strings when the stream runs in parallel.

JAVA
String names = staff.stream()
    .map(Employee::getName)
    .reduce("",
        (a, b) -> a.isEmpty() ? b : a + ", " + b,
        (s1, s2) -> s1.isEmpty() ? s2 : (s2.isEmpty() ? s1 : s1 + ", " + s2));

Why is this O(n^2)?

Each + creates a new String object, copying all previous characters. For n names, the total work is 1 + 2 + 3 + ... + n = O(n^2).

What are common mistakes?

Mistake: not guarding the first element, producing a leading comma.

JAVA
// WRONG: leading comma before the first name
String wrong = staff.stream()
    .map(Employee::getName)
    .reduce("", (a, b) -> a + ", " + b);
// ", Rajesh, Priya, Amit" ← leading comma!

// CORRECT: check if running string is empty
String correct = staff.stream()
    .map(Employee::getName)
    .reduce("", (a, b) -> a.isEmpty() ? b : a + ", " + b);
// "Rajesh, Priya, Amit"

What is the production alternative?

JAVA
// O(n) with StringBuilder internally
String names = staff.stream()
    .map(Employee::getName)
    .collect(Collectors.joining(", "));

Collectors.joining is both simpler and more efficient. The reduce approach is for demonstrating the fold.

What about an empty stream?

With the identity "", an empty stream returns "", which is a correct empty result.

What should a senior engineer know?

  • Never use reduce with string concatenation in production; use Collectors.joining.
  • The reduce approach demonstrates folding mechanics, which is why interviews ask for it.
  • The combiner must handle empty partials correctly for parallel correctness.
  • In Java 11+, String.isBlank() is available but isEmpty() is the correct check here (we want non-whitespace check).

What are common interview follow-up questions?

  • "Why not use reduce for string concatenation in production?" O(n^2) performance.
  • "What does Collectors.joining use internally?" StringBuilder via StringJoiner.
  • "What happens with an empty stream?" Returns the empty string identity.

Visual Overview

DIAGRAM
  reduce("", (a, b) -> a.isEmpty() ? b : a + ", " + b)

  Step 1:  "" + "Rajesh"       → "Rajesh"           (empty check)
  Step 2:  "Rajesh" + "Priya"  → "Rajesh, Priya"
  Step 3:  "Rajesh, Priya" + "Amit" → "Rajesh, Priya, Amit"

  Result: "Rajesh, Priya, Amit"

  Production alternative:
  Collectors.joining(", ")  ← O(n) with StringBuilder

Key Takeaway

To concatenate names with reduce I map each employee to its name, then fold starting from an empty string. The accumulator checks if the running string is empty to avoid a leading comma, then appends the separator and the next name.

The combiner must also handle empty partials for parallel correctness. The result for an empty stream is the empty string identity.

The critical point is that string concatenation in reduce is O(n^2). In production I always use Collectors.joining(", "), which uses a StringBuilder for O(n) performance. The reduce form demonstrates the folding mechanics, which is what the interview tests.

Remember one sentence: reduce can concatenate strings but is O(n^2); use Collectors.joining in production for O(n) StringBuilder-backed concatenation.

---

Share
Use ← → arrow keys to navigate