Definition
- **IntStream.range(0, 5)** produces 0, 1, 2, 3, 4 (exclusive end: 5 elements).
- **mapToObj(i -> "a")** maps each index to the string "a" (ignoring the index value).
- **reduce("", (a, b) -> a + b)** concatenates from the empty identity: "" + "a" + "a" + ... = "aaaaa".
- **String concatenation in reduce** is O(n^2); use `Collectors.joining()` in production.Priya at National Bank of India writes the letter 'a' five times and glues them end to end, starting from an empty string, giving 'aaaaa'.
Understanding the Concepts
What is the output?
The output is the string "aaaaa".
How does each step work?
package com.bank.core;
import java.util.stream.IntStream;
import java.util.stream.Collectors;
public class ReduceConcatDemo {
public static void main(String[] args) {
String result = IntStream.range(0, 5)
.mapToObj(i -> "a")
.reduce("", (a, b) -> a + b);
System.out.println("Result: \"" + result + "\"");
System.out.println("Length: " + result.length());
// Better alternative: Collectors.joining()
String better = IntStream.range(0, 5)
.mapToObj(i -> "a")
.collect(Collectors.joining());
System.out.println("Joining: \"" + better + "\"");
}
}
Result: "aaaaa"
Length: 5
Joining: "aaaaa"
Step-by-step trace
| Step | Accumulator | Element | Result |
|---|---|---|---|
| Start | "" | - | "" |
| 1 | "" | "a" | "a" |
| 2 | "a" | "a" | "aa" |
| 3 | "aa" | "a" | "aaa" |
| 4 | "aaa" | "a" | "aaaa" |
| 5 | "aaaa" | "a" | "aaaaa" |
Why is range(0, 5) five elements, not six?
IntStream.range(start, end) is exclusive on the end: it produces start through end - 1. So range(0, 5) gives 0, 1, 2, 3, 4 (five values). For inclusive, use rangeClosed(0, 5) which gives 0 through 5 (six values).
Why is string concatenation in reduce inefficient?
Each + creates a new String object, copying all previous characters. For n elements, this is O(n^2) total work. Collectors.joining() uses a StringBuilder internally, which is O(n).
// O(n^2): each + copies all previous chars
.reduce("", (a, b) -> a + b)
// O(n): StringBuilder appends without copying
.collect(Collectors.joining())
What are common mistakes?
Mistake: Off-by-one on range.
// range(0, 5) gives 5 elements: [0, 1, 2, 3, 4]
// rangeClosed(0, 5) gives 6 elements: [0, 1, 2, 3, 4, 5]
What about rangeClosed instead of range?
rangeClosed(0, 5) gives 6 elements (0 through 5 inclusive), not 5. Using rangeClosed here would produce "aaaaaa" (6 a's).
How does this pattern apply in banking code?
At National Bank of India, Rajesh generates a reference code by repeating a character prefix for each approval level. The pattern is the same – map indices to strings and join them.
package com.bank.service;
import java.util.stream.IntStream;
import java.util.stream.Collectors;
public class ReferenceCodeGenerator {
public static String generateCode(String prefix, int levels) {
// WRONG: O(n^2) string concatenation
// return IntStream.range(0, levels)
// .mapToObj(i -> prefix)
// .reduce("", (a, b) -> a + b);
// CORRECT: O(n) using Collectors.joining()
return IntStream.range(0, levels)
.mapToObj(i -> prefix)
.collect(Collectors.joining("-"));
}
public static void main(String[] args) {
String code = generateCode("SAV", 4);
System.out.println("Ref code: " + code);
// Output: Ref code: SAV-SAV-SAV-SAV
}
}
Ref code: SAV-SAV-SAV-SAV
Collectors.joining("-") adds a delimiter between elements, which reduce cannot do cleanly without extra logic.
What should a senior engineer know?
The answer is "aaaaa", but in production code, never reduce-concatenate strings. Use Collectors.joining() which uses StringBuilder internally for O(n) performance. For account SAV2001 batch processing at National Bank of India, a reduce-based concatenation on 10,000 transaction descriptions would create 10,000 intermediate String objects. Collectors.joining() avoids this entirely.
What are common interview follow-up questions?
- "How many elements does range(0, 5) produce?" Five (exclusive end).
- "Why not use reduce for string concatenation?" O(n^2) due to immutable String copying.
- "What is the production alternative?"
Collectors.joining().
Visual Overview
IntStream.range(0, 5) → [0, 1, 2, 3, 4] (5 elements)
│
│ mapToObj(i -> "a")
▼
["a", "a", "a", "a", "a"]
│
│ reduce("", (a, b) -> a + b)
│
│ "" + "a" = "a"
│ "a" + "a" = "aa"
│ "aa" + "a" = "aaa"
│ "aaa" + "a" = "aaaa"
│ "aaaa" + "a" = "aaaaa"
▼
Result: "aaaaa"
Key Takeaway
The output is "aaaaa". IntStream.range(0, 5) produces five indices (exclusive end), mapToObj maps each to the string "a", and reduce concatenates them from the empty identity. The two tricky points are: range is exclusive (five elements, not six), and string concatenation in reduce is O(n^2) because each + copies all previous characters.
At the National Bank of India, Rajesh uses Collectors.joining() instead of reduce for string concatenation because it uses a StringBuilder internally for O(n) performance. The reduce approach is correct for interviews but not for production.
Remember one sentence: range(0, 5) gives five elements (exclusive end), and reducing with string concatenation produces "aaaaa" but should use joining() in production for O(n) performance.
---