Back to Stream Creation & Utilities
Q15Question 15 of 18

Generate a stream of powers of 2 using Stream.iterate(1, n -> n * 2).limit(10)

Key Concepts
  • Stream.iterate(1, n -> n * 2) seeds at 1 and doubles each value, generating powers of two
  • Unlike Fibonacci, doubling depends on only one predecessor, so no pair encoding is needed
  • limit(10) bounds the infinite stream to the first 10 powers: 1, 2, 4, 8, ..., 512
  • int overflows at 2^31 (31st power); long overflows at 2^63 (63rd power)
  • For large exponents, use BigInteger to avoid overflow
  • This is a clean functional expression of a geometric sequence

Definition

`Stream.iterate(1, n -> n * 2).limit(10)` yields the first ten powers of two: 1, 2, 4, 8, ..., 512.
  • **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: int at 2^31, long at 2^63; use BigInteger for 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?

JAVA
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);
    }
}
TEXT
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?

DIAGRAM
| 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?

JAVA
// 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.

JAVA
// 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)?

JAVA
// 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?

JAVA
// 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.iterate or LongStream.iterate.

Visual Overview

DIAGRAM
  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.

---

Share
Use ← → arrow keys to navigate