Definition
- **Stream.iterate(1, n -> n * 2)** seeds at 1 and applies the doubling operator repeatedly.
- Single-value state: doubling depends only on the previous value, so no pair is needed.
- limit(10) takes the first ten: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512.
- Overflow:
intat 2^31,longat 2^63; useBigIntegerfor larger exponents. - Geometric sequence: this is the functional way to express doubling.
Rajesh at National Bank of India starts with 1 and keeps doubling: 1, 2, 4, 8. He stops after ten steps, giving the first ten powers of two for an exponential backoff retry configuration.
Understanding the Concepts
How does iterate generate powers of two?
Stream.iterate(1, n -> n * 2) starts with the seed value 1 and applies the doubling function to produce each subsequent value: 1, 2, 4, 8, 16, and so on. Each power of two depends only on the single previous value, so the unary operator on one integer suffices. No pair encoding is needed, unlike Fibonacci.
How do you implement it?
package com.bank.core;
import java.util.List;
import java.util.stream.Stream;
public class PowersOfTwo {
public static void main(String[] args) {
List<Long> powers = Stream.iterate(1L, n -> n * 2)
.limit(10)
.toList();
System.out.println("Powers of 2: " + powers);
// Banking use case: exponential backoff delays in milliseconds
List<Long> backoffDelays = Stream.iterate(100L, d -> d * 2)
.limit(8)
.toList();
System.out.println("Backoff delays (ms): " + backoffDelays);
}
}
Powers of 2: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Backoff delays (ms): [100, 200, 400, 800, 1600, 3200, 6400, 12800]
How is this different from Fibonacci?
| Aspect | Powers of 2 | Fibonacci |
|---|---|---|
| Predecessors needed | 1 (just double the last) | 2 (sum of last two) |
| State carried | Single value | Pair {a, b} |
| Operator | `n -> n * 2` | `{a,b} -> {b, a+b}` |
| Map step needed | No | Yes: `map(f -> f[0])` |What about overflow?
// int overflows at the 31st power of 2
int intMax = Integer.MAX_VALUE; // 2^31 - 1 = 2,147,483,647
// long overflows at the 63rd power of 2
long longMax = Long.MAX_VALUE; // 2^63 - 1
// BigInteger for arbitrary precision
import java.math.BigInteger;
List<BigInteger> largePowers = Stream.iterate(
BigInteger.ONE, n -> n.multiply(BigInteger.TWO))
.limit(100)
.toList();
// No overflow even at 2^99
What are common mistakes?
Mistake: Forgetting to bound the infinite stream.
// WRONG: no limit, runs forever
Stream.iterate(1, n -> n * 2)
.forEach(System.out::println); // never terminates
// CORRECT: always limit infinite streams
Stream.iterate(1, n -> n * 2)
.limit(10)
.forEach(System.out::println);
What about the three-argument iterate (Java 9)?
// Powers of 2 up to 1000
List<Integer> powersUpTo1000 = Stream.iterate(1, n -> n <= 1000, n -> n * 2)
.toList();
// [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
// Self-terminating: no limit needed
What about using IntStream for primitives?
// Avoid boxing with IntStream
int[] powers = java.util.stream.IntStream.iterate(1, n -> n * 2)
.limit(10)
.toArray();
// Returns int[] directly, no Integer boxing
What should a senior engineer know?
The contrast with Fibonacci illustrates a key principle: the amount of state carried in iterate is dictated by how many predecessors the recurrence needs. Doubling needs only one predecessor, so a single value suffices. Fibonacci needs two, so a pair is required. This generalizes to any k-order recurrence.
What are common interview follow-up questions?
- "Why is no pair needed here?" Doubling depends on only the last value, not the last two.
- "When does long overflow?" At 2^63.
- "How do you generate powers of 3?" Change the operator to
n -> n * 3. - "How do you avoid boxing?" Use
IntStream.iterateorLongStream.iterate.
Visual Overview
Stream.iterate(1, n -> n * 2)
│
│ Step 0: seed = 1
│ Step 1: 1 * 2 = 2
│ Step 2: 2 * 2 = 4
│ Step 3: 4 * 2 = 8
│ Step 4: 8 * 2 = 16
│ ...continuing...
│
│ limit(10)
▼
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Key Takeaway
Stream.iterate seeded at 1 with a doubling operator generates powers of two: 1, 2, 4, 8, and so on. Unlike Fibonacci, each power of two depends only on the single previous value, so no pair encoding is needed. limit(10) takes the first ten values.
At the National Bank of India, Rajesh uses this pattern to generate exponential backoff delays for a retry utility: start at 100ms and double each time. The geometric sequence is a clean functional expression that replaces manual loop-and-multiply code.
The key differences from Fibonacci are the state requirement (one value vs. a pair) and overflow timing (int at 2^31, long at 2^63). For large exponents, switch to BigInteger. For primitives, use IntStream.iterate or LongStream.iterate to avoid boxing.
Remember one sentence: iterate(1, n -> n * 2).limit(10) generates powers of two with a single-value state because doubling depends only on the last term.
---