W3docs

Creating Java Streams

Create Java streams from collections, arrays, Stream.of, Stream.iterate, Stream.generate, and IO sources.

Creating Java Streams

The intro chapter showed the pipeline shape — source → intermediates → terminal — and treated the source as a given. This chapter is the catalogue of sources. Every stream pipeline you write begins with one of them, and each one has a small set of habits that decide whether the pipeline that follows is correct, lazy, finite, ordered, or parallelisable.

The list is shorter than it looks. Almost every stream you'll ever write starts with one of coll.stream(), Stream.of(...), Arrays.stream(arr), or an IntStream.range. The rest of this chapter is "and here are the few situations where the others are the right call."

From a Collectioncoll.stream()

The dominant source. Collection<T> has a default stream() method, so every List, Set, Queue, and Deque exposes one for free:

List<String> names = List.of("Alice", "Bob", "Carol");
long count = names.stream().filter(n -> n.length() > 3).count();

The stream is sequential, sized (the JVM knows the element count up front), and ordered if the collection is. A List produces an ordered stream; a HashSet produces an unordered one; a TreeSet produces an ordered one sorted by the set's comparator.

There's also coll.parallelStream(), which schedules across the common ForkJoinPool. Same source, different execution policy — covered in Java Parallel Streams.

From explicit elements — Stream.of(...)

Use Stream.of when you have a short, known list of elements and don't want a throwaway List:

Stream<String> s   = Stream.of("a", "b", "c");
Stream<Integer> n  = Stream.of(1, 2, 3, 4, 5);
Stream<Object> one = Stream.of("just one");

It's a varargs method, so it takes any number of arguments (zero is allowed and yields an empty stream). With a single T[] argument the compiler picks Stream.of(T...), not Stream.of(T) — handy when you already have an array:

String[] arr = {"x", "y", "z"};
Stream<String> fromArr = Stream.of(arr);   // same as Arrays.stream(arr)

From an array — Arrays.stream(...)

Arrays.stream has overloads for T[], int[], long[], double[], plus range variants:

int[] xs = {3, 1, 4, 1, 5, 9, 2, 6};
IntStream ix = Arrays.stream(xs);              // primitive specialisation
IntStream tail = Arrays.stream(xs, 2, xs.length);   // half-open [2, len)

String[] words = {"alpha", "beta", "gamma"};
Stream<String> ws = Arrays.stream(words);

The primitive overloads return IntStream, LongStream, DoubleStream — not Stream<Integer>. That matters: primitive streams skip boxing, have sum, average, min, max directly (no collector), and play well with mapToInt/mapToObj to move between worlds.

Primitive ranges — IntStream.range / rangeClosed

The fastest way to iterate by index without a for loop:

// 0, 1, 2, ..., 9
IntStream.range(0, 10).forEach(i -> System.out.println(i));

// 1..10 inclusive
int sum = IntStream.rangeClosed(1, 10).sum();   // 55

range(a, b) is half-open [a, b). rangeClosed(a, b) is [a, b]. Both are bounded, ordered, sized, and faster than Stream.iterate(0, i -> i + 1).limit(n) because the JVM knows the count up front. Use them whenever a loop's body is "do something at index i."

To couple an index to a List's elements you write:

List<String> names = List.of("Alice", "Bob", "Carol");
IntStream.range(0, names.size())
    .mapToObj(i -> i + ": " + names.get(i))
    .forEach(System.out::println);

Generated infinite streams — Stream.iterate and Stream.generate

Two ways to produce an unbounded stream. They look similar; they're not the same.

Stream.iterate(seed, f) — start with seed, then f(seed), then f(f(seed)), …. Ordered, deterministic, sequential. Almost always followed by a short-circuit:

Stream.iterate(1, n -> n * 2)
    .limit(10)
    .forEach(System.out::println);   // 1, 2, 4, 8, ..., 512

There's also a 3-arg overload Stream.iterate(seed, hasNext, next) (Java 9+) that bakes the stop condition into the source — no limit needed:

Stream.iterate(1, n -> n < 1000, n -> n * 2).forEach(System.out::println);

Stream.generate(supplier) — calls a Supplier<T> repeatedly. Unordered, no relationship between elements:

Stream.generate(Math::random).limit(5).forEach(System.out::println);
Stream.generate(() -> "ping").limit(3).forEach(System.out::println);

Use iterate for sequences where each term depends on the previous (n -> n + 1, n -> n * 2, the Fibonacci pair arr -> {arr[1], arr[0] + arr[1]}). Use generate for independent values from a side source — random numbers, fixed constants, UUIDs.

Either way, always terminate them with a short-circuiting operation: limit(n), the 3-arg iterate, or a terminal like findFirst / anyMatch. A plain toList() on an infinite stream hangs the JVM.

From I/O — Files.lines, BufferedReader.lines

Files.lines(path) opens a file and returns a Stream<String> of its lines. Lazy: lines are read as the pipeline pulls them, not up front:

try (Stream<String> lines = Files.lines(Path.of("words.txt"))) {
    long longWords = lines.filter(w -> w.length() > 8).count();
}

The try-with-resources is mandatory. The stream holds an open file handle, and the only way to release it is to call close() — which try-with-resources does for you. Without it the descriptor leaks until the stream is garbage-collected, which can be never under load.

Same shape for Readers via BufferedReader.lines(). Both are the canonical way to walk a text file without loading it into memory.

String.chars() and String.codePoints()

A String is a sequence of UTF-16 code units; the API exposes both views:

"hello".chars()                   // IntStream of UTF-16 code units
       .filter(Character::isUpperCase)
       .count();

"héllo".codePoints()              // IntStream of Unicode code points
       .mapToObj(Character::toString)
       .forEach(System.out::println);

Both return IntStream. chars() is fine for ASCII; for anything that might contain surrogate pairs (most emoji, many scripts), codePoints() is the safe choice.

Empty and single-element streams

For default cases and flatMap branches:

Stream<String> none = Stream.empty();          // 0 elements
Stream<String> one  = Stream.of("x");          // exactly 1
Stream<String> opt  = Optional.of("x").stream();   // 1 if present, else empty

Optional.stream() (Java 9+) is the bridge between Optional<T> and Stream<T> — handy when you flatMap a stream of Optionals into a stream of present values without any null bookkeeping.

Stream.Builder — pushing elements one at a time

When you can't express the source as a literal, an array, or a generator — usually because elements come from disparate branches of imperative code — there's a builder:

Stream.Builder<String> b = Stream.builder();
b.add("first");
if (someCondition) b.add("second");
b.accept("third");
Stream<String> s = b.build();

After build() the builder is sealed; further add throws. It's a rare-but-honest tool. Most code that reaches for it is better written with an ArrayList<String> followed by list.stream(), but the builder avoids that intermediate when the data is built piecewise.

Map streams — there isn't one

Map<K, V> has no stream() method. You stream its views instead:

Map<String, Integer> ages = Map.of("Alice", 30, "Bob", 25);
ages.entrySet().stream().filter(e -> e.getValue() >= 18).map(Map.Entry::getKey).toList();
ages.keySet().stream().sorted().toList();
ages.values().stream().mapToInt(Integer::intValue).sum();

entrySet().stream() is what you want most often — both halves of each entry are in scope, and Map.Entry::getKey / ::getValue work as method references.

Picking the right source

SituationUse
You already have a List, Set, Queuecoll.stream()
You have a few fixed elementsStream.of(a, b, c)
You have a T[]Arrays.stream(arr)
You have int[], long[], double[]Arrays.stream(arr) → primitive stream
You want to loop by indexIntStream.range(0, n)
You want each term from the previousStream.iterate
You want independent samplesStream.generate
You want lines of a text fileFiles.lines(path) inside try-with-resources
You want characters of a String"...".chars() or .codePoints()
You want a fallback empty streamStream.empty()
You're stuck building piecewiseStream.builder()
You want to stream a Mapmap.entrySet().stream()

That table covers everything in the chapter, and probably 99% of real code.

A worked example: ten sources, one program

The program below builds one stream from each of the major sources, runs a tiny terminal against it so the output is visible, and prints both the result and the kind of source it came from.

java— editable, runs on the server

What to take from the run:

  • Every line in the output came from a different source, but they all flow into the same intermediate/terminal vocabulary. The choice of source decides what the pipeline can start with; it does not change what comes after.
  • Arrays.stream(int[]) produced an IntStreamsum() is right there on the stream, no boxing, no Collectors.summingInt. The primitive specialisations matter on numeric pipelines.
  • The two Stream.iterate calls show the difference between iterate(seed, f) + limit(n) (you pick the count) and the 3-arg iterate(seed, hasNext, next) (the source picks the count). Both are bounded; an iterate without a bound and without a short-circuiting terminal is the classic JVM-hangs-forever bug.
  • Stream.empty() and Optional.of(...).stream() are how empty and single-element streams enter a pipeline — typically inside a flatMap branch where some inputs produce zero or one downstream element.
  • Stream.builder() is the escape hatch for the (rare) case where the source is built imperatively across branches. Most real code reaches for coll.stream() first.

What's next

You can now build any stream you need from any source you actually have. The next two chapters cover the operations that run between the source and the result. First, Java Stream Intermediate Operationsfilter, map, flatMap, distinct, sorted, peek, limit, skip — the lazy transformations that reshape the stream without running it. Then the terminals that produce the value.

Practice

Practice

Which of these is the *cheapest* way to iterate the integers `0` through `99`, in order, as a stream?