skip to content

Streams API

Stream pipelines end to end: sources, intermediate and terminal operations, the lazy fused execution model, collectors, primitive streams and parallelism. Expect at least one live coding question that turns a loop into a pipeline, plus follow-ups on why the pipeline behaves as it does.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

89 · 17 sections

What are the common ways to create a Stream in Java from existing data such as a collection, an array, or a few known values?

level: juniorimportance: must knowfreq 78%
basics
~10 s

Call collection.stream() on a List, Set, or Map's entries; use Arrays.stream(array) for arrays; Stream.of(a, b, c) for a handful of values; and Stream.empty() for an empty stream.

open as a page

How do Stream.iterate and Stream.generate create infinite streams, and how do you make such a pipeline terminate?

level: middleimportance: must knowfreq 70%
basics
~10 s

Stream.iterate(seed, x -> next) and Stream.generate(supplier) produce endless streams. You must add a short-circuiting operation like limit(n) (or takeWhile/findFirst) so the pipeline stops; otherwise it runs forever.

open as a page

How do you generate a stream of consecutive integers in Java, and what is the difference between IntStream.range and IntStream.rangeClosed?

level: juniorimportance: should knowfreq 58%
basics
~10 s

Use IntStream.range(start, end) for start up to end-1 (end excluded), or IntStream.rangeClosed(start, end) to include end. Both return an IntStream of consecutive ints.

open as a page

How do you create a Stream over the lines of a file with Files.lines, and what resource-management concern does it introduce?

level: seniorimportance: should knowfreq 48%
basics
~10 s

Files.lines(path) returns a Stream<String> of the file's lines, read lazily. It holds an open file handle, so you must close it — wrap it in try-with-resources, since Stream is AutoCloseable.

open as a page

What is a Spliterator, and what role does it play as the underlying source of every Java stream?

level: seniorimportance: should knowfreq 40%
basics
~20 s

A Spliterator is the object that actually feeds a stream: it knows how to traverse elements one by one (tryAdvance) and how to split itself into chunks (trySplit) so a parallel stream can process pieces on different threads.

open as a page

What are the three structural parts of a Java Stream pipeline, and what is the role of each?

level: juniorimportance: must knowfreq 78%
basics
~20 s

A stream pipeline has a source (where data comes from, like a list), zero or more intermediate operations (like filter or map that transform the stream), and exactly one terminal operation (like collect or forEach) that produces a result and runs the pipeline.

open as a page

How does a Stream differ from a Collection in Java?

level: middleimportance: must knowfreq 74%
basics
~20 s

A Collection stores data in memory and you can access it many times. A Stream stores nothing — it just describes a computation over a source and can only be used once, after which it is finished.

open as a page

What is the single-use constraint of a Java Stream, and what happens if you violate it?

level: middleimportance: should knowfreq 66%
basics
~20 s

A stream can only be operated on once. After you call a terminal operation (or even a second intermediate op), the stream is consumed. Trying to reuse it throws IllegalStateException with a message like 'stream has already been operated upon or closed'.

open as a page

Explain how stream laziness enables operation fusion and short-circuiting, and what defeats these optimizations.

level: seniorimportance: should knowfreq 52%
basics
~20 s

Because intermediate operations don't run until the terminal operation, the stream can push each element through the whole chain in one pass (fusion) and stop early once it has enough (short-circuiting, e.g. with findFirst or limit). Stateful operations like sorted or distinct that must see many elements at once break the single-pass flow.

open as a page

What is a Spliterator and what role does it play as the source abstraction behind a stream pipeline?

level: seniorimportance: should knowfreq 48%
basics
~20 s

A Spliterator is the object that feeds elements from a source into a stream, one at a time. It is like an iterator that can also split itself in two, which is how streams divide work for parallel processing.

open as a page

In Java's Streams API, what is the difference between intermediate and terminal operations, and why does nothing happen until a terminal operation is called?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Intermediate operations like map and filter are lazy: they only set up a plan and return a new stream. Nothing actually runs until you call a terminal operation like collect, forEach, or count, which triggers the work.

open as a page

How does a stream pipeline like source.filter(...).map(...).forEach(...) actually traverse elements — does it build an intermediate filtered list, and in what order are the operations applied?

level: middleimportance: must knowfreq 70%
basics
~20 s

No intermediate lists are built. Each element flows through the whole chain one at a time: an element is filtered, then if it passes, mapped, then handled by forEach, before the next element starts. The operations are fused into a single pass.

open as a page

Why does peek sometimes print fewer elements than the source contains, for example in stream.peek(...).limit(2).collect(...)? Explain in terms of the execution model.

level: middleimportance: should knowfreq 58%
basics
~20 s

Because peek only runs for elements that are actually pulled through the pipeline. A short-circuiting op like limit(2) stops after two elements are produced, so the engine never asks the source for more, and peek never sees the rest.

open as a page

Explain the difference between stateless and stateful intermediate stream operations, and why stateful ones (sorted, distinct, limit) interfere with the otherwise lazy, single-pass execution.

level: seniorimportance: should knowfreq 40%
basics
~20 s

Stateless ops like map and filter handle each element on its own, so they pipeline cleanly. Stateful ops like sorted, distinct, limit, and skip need to remember earlier elements (or count them), so they may buffer or block the single-pass flow.

open as a page

From a design standpoint, why did Java make stream intermediate operations lazy instead of eager like collection transformations, and what classes of optimization does that unlock?

level: seniorimportance: should knowfreq 44%
basics
~20 s

Laziness lets the whole pipeline run in one pass without building throwaway intermediate collections, and lets the engine stop early (short-circuit) and reorder/parallelize work. An eager design would materialize a new collection after every step and could never short-circuit.

open as a page

In the Java Streams API, what is the difference between a stateless and a stateful intermediate operation? Give examples of each.

level: juniorimportance: must knowfreq 60%
basics
~10 s

A stateless operation processes each element on its own, knowing nothing about other elements (map, filter, flatMap, peek). A stateful operation needs to see other elements to produce its result (distinct, sorted, limit, skip).

open as a page

How do stateful operations like sorted and distinct affect a stream pipeline's lazy single-pass fusion and memory behavior?

level: middleimportance: must knowfreq 50%
basics
~20 s

Normally elements flow through the whole pipeline one at a time. A stateful op like sorted has to gather elements first, so it buffers them and stops that one-at-a-time flow until it has what it needs, using more memory.

open as a page

You build an infinite stream with Stream.iterate and add sorted(). What happens, and which intermediate operations are safe on an infinite stream?

level: middleimportance: should knowfreq 35%
basics
~20 s

sorted hangs forever (or runs out of memory) because it must see every element first, and an infinite stream never ends. Stateless ops like map and filter, plus the short-circuiting limit, are safe on infinite streams.

open as a page

Why do stateful stream operations hurt parallel-stream performance more than stateless ones?

level: seniorimportance: should knowfreq 45%
basics
~10 s

Parallel streams split data across threads and process chunks independently. Stateless ops parallelize cleanly. Stateful ops like sorted or distinct must combine results across threads, which adds synchronization and buffering, so they scale worse.

open as a page

As a tech lead, what guidance would you give about using stateful stream operations in performance-sensitive or parallel code paths?

level: principalimportance: nice to knowfreq 25%
basics
~20 s

Prefer stateless ops in hot paths; keep filters before stateful ops like sorted to shrink what they buffer; benchmark before using parallel streams with sorted/distinct, since their cross-thread coordination can make parallel slower than sequential.

open as a page

What does it mean for a Stream operation to be short-circuiting, and why does it matter?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A short-circuiting operation can stop processing elements as soon as the result is decided, instead of looking at every element. For example, anyMatch stops at the first matching element. This saves work and lets pipelines over very large or infinite streams finish.

open as a page

How do anyMatch, allMatch, and noneMatch short-circuit, and what do they return on an empty stream?

level: middleimportance: must knowfreq 58%
basics
~20 s

All three are short-circuiting terminals returning a boolean. anyMatch stops and returns true at the first match; allMatch stops and returns false at the first element that fails; noneMatch stops and returns false at the first match. On an empty stream: anyMatch is false, while allMatch and noneMatch are both true (vacuously).

open as a page

What is the difference between findFirst and findAny, and why do both return Optional?

level: middleimportance: should knowfreq 60%
basics
~20 s

Both are short-circuiting terminals that return one element wrapped in an Optional (empty if the stream had none). findFirst always returns the first element in encounter order. findAny may return any element — which lets it run faster in parallel because it doesn't have to respect order.

open as a page

How does takeWhile differ from filter, and how does it relate to limit?

level: middleimportance: should knowfreq 55%
basics
~20 s

filter keeps every element that matches the condition, scanning the whole stream. takeWhile keeps elements from the start only while the condition holds, and stops at the first element that fails — so it short-circuits. limit is similar but cuts off by count instead of by a condition.

open as a page

How does short-circuiting interact with parallel streams and encounter order, and what are the pitfalls?

level: seniorimportance: should knowfreq 38%
basics
~20 s

Short-circuiting still works in parallel — once one thread finds the deciding element, the others can stop. But operations that must respect encounter order (findFirst, limit, takeWhile) need extra coordination across threads, which can cancel out the parallel speed-up. Order-independent ones (anyMatch, findAny) parallelize cleanly.

open as a page

What is encounter order in the Java Streams API, and what determines whether a stream has one?

level: juniorimportance: must knowfreq 55%
basics
~20 s

Encounter order is the order a stream's elements are processed in. A stream has it when its source is ordered, like a List or an array. Sources like HashSet have no defined order, so their streams are unordered.

open as a page

What is the difference between findFirst() and findAny() on a stream, and when would you prefer each?

level: middleimportance: must knowfreq 60%
basics
~10 s

findFirst() returns the first element in encounter order. findAny() returns any matching element, with no order promise. Use findFirst when order matters; prefer findAny in parallel streams because it can be faster.

open as a page

What is the difference between forEach() and forEachOrdered() on a stream, especially when the stream is parallel?

level: middleimportance: must knowfreq 52%
basics
~20 s

forEach() runs an action on each element with no order guarantee — in a parallel stream elements may be handled in any order. forEachOrdered() always processes elements in encounter order, even in parallel, at the cost of speed.

open as a page

What does the unordered() intermediate operation do, and how can it improve parallel stream performance?

level: seniorimportance: should knowfreq 38%
basics
~20 s

unordered() is a hint that tells the stream it no longer needs to preserve encounter order. It does not reorder anything itself, but it frees parallel operations like distinct() and limit() to skip the bookkeeping that maintaining order requires, which can be faster.

open as a page

When designing a parallel stream pipeline, how do you reason about encounter order to keep results both correct and performant?

level: principalimportance: should knowfreq 30%
basics
~20 s

Decide whether your result depends on order. If it does, keep an ordered source and use order-respecting operations (findFirst, forEachOrdered, collect to List). If order is irrelevant, use unordered sources or unordered()/findAny to let parallelism run faster. Never rely on accidental ordering.

open as a page

Explain the difference between map and filter as stream intermediate operations, including how they affect element count and type.

level: juniorimportance: must knowfreq 80%
basics
~20 s

filter keeps only elements that match a condition, so it can shrink the stream but never changes element type. map transforms each element into a new value (possibly a different type) one-for-one, so it keeps the same number of elements but can change what they are.

open as a page

What are intermediate operations in the Java Streams API, and what does it mean that they are lazy?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Intermediate operations like map, filter, and sorted transform a stream and return a new stream, so you can chain them. They are lazy: nothing actually runs until you add a terminal operation (such as collect or forEach) at the end.

open as a page

What is the difference between stateful and stateless intermediate operations in the Streams API? Give examples and explain why it matters.

level: middleimportance: must knowfreq 70%
basics
~20 s

A stateless operation (like map, filter, peek) handles each element on its own without remembering others. A stateful operation (like distinct, sorted, limit, skip) needs to remember or see other elements to do its job, so it may have to buffer data. Stateful ops cost more and can hurt parallel performance.

open as a page

When and how should you use peek() and sorted() (including a custom comparator)? What are the pitfalls of each?

level: middleimportance: should knowfreq 58%
basics
~20 s

peek lets you look at each element as it flows by, mainly for debugging or logging, without changing it. sorted orders the stream, either by natural order or by a Comparator you pass in. Pitfalls: peek may not run for every element (and shouldn't change state), and sorted must buffer the whole stream and needs Comparable elements if you give no comparator.

open as a page

Compare limit/skip with takeWhile/dropWhile (Java 9). How do they behave on ordered vs unordered and infinite streams?

level: seniorimportance: should knowfreq 52%
basics
~20 s

limit(n) keeps the first n elements and skip(n) drops the first n, both by position. takeWhile keeps elements from the start as long as a condition is true and stops at the first failure; dropWhile drops the leading run that matches and keeps the rest. limit and takeWhile can stop a stream early, so they work on infinite streams; skip and dropWhile generally must process the leading part.

open as a page

What is the difference between Stream.map and Stream.flatMap in Java?

level: juniorimportance: must knowfreq 85%
basics
~20 s

map transforms each element into exactly one new element (one-to-one). flatMap turns each element into a stream of elements and merges them all into one flat stream (one-to-many), so you end up with more or fewer elements, not the same count.

open as a page

How would you use flatMap to flatten a nested collection and split text into words, and why can't map do it?

level: middleimportance: should knowfreq 70%
basics
~20 s

Use flatMap with a function that turns each element into a stream — e.g. List::stream to flatten a List<List<X>>, or splitting each line into a stream of words. map can't because it would give one nested stream per element (a stream of streams) instead of merging them.

open as a page

What happens to the inner streams that flatMap produces, and why does that matter for resources like Files.lines?

level: seniorimportance: should knowfreq 45%
basics
~20 s

flatMap consumes each inner stream it creates and closes it when done. That matters because some streams hold resources — like Files.lines opening a file — so flatMap closing them after consumption helps avoid leaking file handles.

open as a page

What is Stream.mapMulti (Java 16), and when would you prefer it over flatMap?

level: principalimportance: nice to knowfreq 25%
basics
~20 s

mapMulti is a Java 16 stream method that, like flatMap, lets each element produce zero or more outputs — but instead of returning a stream, you push results into a consumer. It avoids creating a small stream per element, so it can be faster and allocate less when each element yields few results.

open as a page

What does it mean that a stream is 'consumed' after a terminal operation, and what happens if you reuse it?

level: juniorimportance: must knowfreq 62%
basics
~10 s

After you call a terminal operation, the stream is used up. Calling another operation on the same stream throws IllegalStateException. To process the data again you must create a brand-new stream from the source.

open as a page

What is a terminal operation in the Java Streams API, and how does it differ from an intermediate operation?

level: juniorimportance: must knowfreq 78%
basics
~20 s

A terminal operation ends a stream and produces a result or side effect, like collect, forEach, count, or reduce. Intermediate operations (map, filter) just describe steps and return another stream. Only a terminal operation actually runs the pipeline.

open as a page

Compare reduce and collect: when would you use each, and why is collect preferred for building mutable containers?

level: middleimportance: must knowfreq 70%
basics
~20 s

reduce folds elements into one immutable value (like a sum) using a combining function. collect accumulates elements into a mutable container (List, Map, String) using a Collector. Use collect for building collections because it reuses one container instead of creating new ones each step.

open as a page

How do min/max, count, and toArray behave as terminal operations — including the Comparator requirement, the Optional return, and the generator form of toArray?

level: middleimportance: should knowfreq 45%
basics
~20 s

min and max need a Comparator and return an Optional (empty if the stream is empty). count returns the number of elements as a long. toArray() returns an Object[]; use toArray(String[]::new) to get a typed array of the right element type.

open as a page

Explain short-circuiting terminal operations (anyMatch/allMatch/noneMatch, findFirst/findAny) and the edge cases of the match operations on an empty stream.

level: middleimportance: should knowfreq 55%
basics
~20 s

Some terminal ops can stop early once the answer is known. anyMatch returns true as soon as one element matches; allMatch/noneMatch stop at the first counterexample; findFirst/findAny return one element and stop. On an empty stream: anyMatch is false, allMatch and noneMatch are both true.

open as a page

What are the three overloaded forms of Stream.reduce, and what does each return?

level: juniorimportance: must knowfreq 70%
basics
~20 s

reduce folds a stream into one result. The one-arg form (just a combine function) returns an Optional because the stream may be empty. The two-arg form takes a starting value plus a combine function and returns a plain value. The three-arg form adds a combiner used when running in parallel.

open as a page

What correctness laws must identity, accumulator, and combiner satisfy for reduce to give correct (and parallel-safe) results?

level: middleimportance: must knowfreq 60%
basics
~20 s

The identity must be a neutral value: combining it with any element leaves the element unchanged (like 0 for addition). The accumulator must be associative, so the order of grouping doesn't change the answer. And the combiner must give the same result as the accumulator. Break these and parallel results become wrong or nondeterministic.

open as a page

How does reduce behave on an empty stream across its three forms, and how should you handle the Optional result?

level: juniorimportance: should knowfreq 45%
basics
~20 s

On an empty stream the one-arg reduce returns an empty Optional, while the two-arg and three-arg forms return the identity you gave. For the Optional, don't call get() blindly — use orElse, orElseGet, ifPresent, or map so an empty result is handled safely.

open as a page

When should you use reduce versus collect for a reduction, and why?

level: seniorimportance: should knowfreq 65%
basics
~20 s

Use reduce when you combine values into a new immutable result, like summing numbers or finding a max. Use collect when you accumulate into a mutable container, like building a List, Map, or StringBuilder. reduce makes a fresh value each step; collect mutates one container, which is far more efficient for large results.

open as a page

How does reduce decompose a parallel stream, and what makes a reduction a good or bad candidate for parallelization?

level: principalimportance: should knowfreq 35%
basics
~20 s

In a parallel stream, reduce splits the data into chunks, reduces each chunk to a partial result, then merges the partials with the combiner. It pays off only when the data is large, splitting is cheap, the accumulator and combiner are fast and law-abiding, and there's no shared mutable state or boxing overhead.

open as a page

What is mutable reduction in the Java Streams API, and how does collect() perform it?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Mutable reduction combines stream elements by adding them into one mutable container (like a List or StringBuilder) instead of creating a new value each step. collect() does this: it makes a container, then drops each element into it.

open as a page

When would you use the three-argument collect(supplier, accumulator, combiner) instead of collect(Collector), and how do the two forms relate?

level: middleimportance: should knowfreq 55%
basics
~20 s

The three-arg collect lets you spell out the container, how to add an element, and how to merge two containers, all inline. collect(Collector) is the packaged version using ready-made collectors like Collectors.toList(). Prefer the packaged ones; use three-arg for quick one-off containers.

open as a page

What are the three Collector characteristics (CONCURRENT, UNORDERED, IDENTITY_FINISH), and how does each affect parallel collection?

level: seniorimportance: should knowfreq 45%
basics
~20 s

They are hints a Collector gives the stream. CONCURRENT means all threads can safely share one container. UNORDERED means element order doesn't matter so the stream can skip preserving it. IDENTITY_FINISH means the accumulation container is already the final result, so the finisher can be skipped.

open as a page

What contract must the supplier, accumulator, and combiner of a collect() satisfy for a correct parallel result, and what goes wrong if it is violated?

level: seniorimportance: should knowfreq 40%
basics
~20 s

The combiner must produce the same result as accumulating everything into one container. The functions must not interfere with the source or share state badly. If they disagree, a parallel stream gives wrong or random results, even though the sequential version looks fine.

open as a page

When should you choose collect() over reduce() (and vice versa), and how does parallel performance factor in?

level: principalimportance: should knowfreq 38%
basics
~20 s

Use reduce() when combining gives a single immutable value (a sum, max, the smallest object) and combining is cheap. Use collect() when the result is a mutable container (List, Map, String). collect avoids copying a growing container per element, so it scales; reduce on a container would be O(n^2).

open as a page

How do you collect a Stream into a List, and what is the difference between Collectors.toList(), Collectors.toUnmodifiableList(), and Stream.toList()?

level: juniorimportance: must knowfreq 72%
basics
~10 s

Use stream.collect(Collectors.toList()) to get a List. toUnmodifiableList() gives a List you cannot change (add/remove throws). Since Java 16, stream.toList() is a shorter way to get an unmodifiable list.

open as a page

How does Collectors.toMap(keyMapper, valueMapper) work, and what does each function receive and produce?

level: juniorimportance: must knowfreq 68%
basics
~20 s

toMap takes two functions: a keyMapper that turns each element into the map key, and a valueMapper that turns each element into the value. The result is a Map built from those keys and values.

open as a page

Collectors.toMap throws IllegalStateException on duplicate keys. How do you resolve that, and what does the 3-argument merge-function overload do?

level: middleimportance: must knowfreq 63%
basics
~20 s

Add a third argument: a merge function. When two elements produce the same key, the merge function takes the existing value and the new value and returns the one to keep. For example (a, b) -> b keeps the last value.

open as a page

How do you control which concrete Map type Collectors.toMap returns (e.g. a TreeMap or LinkedHashMap), and what does the 4-argument Supplier overload require?

level: middleimportance: should knowfreq 48%
basics
~10 s

Use the four-argument toMap(keyMapper, valueMapper, mergeFunction, mapSupplier). The fourth argument is a supplier like TreeMap::new that creates the map you want. You must also pass a merge function with this overload.

open as a page

Compare the mutability, null-handling, and concurrency guarantees across the Collectors collection/map factories (toList/toSet/toMap vs their unmodifiable and concurrent variants). When does the choice actually matter?

level: seniorimportance: should knowfreq 40%
basics
~10 s

The plain toList/toSet/toMap give a mutable result of unspecified type and mostly tolerate nulls (except toMap values). The toUnmodifiable* variants give immutable results and reject nulls. toConcurrentMap supports thread-safe parallel collection.

open as a page

What does Collectors.groupingBy do, and what is the shape of the result?

level: juniorimportance: must knowfreq 78%
basics
~20 s

groupingBy takes a function that maps each element to a key. It returns a Map where each key points to a list of all the elements that produced that key, like sorting items into labeled buckets.

open as a page

How do you count or aggregate elements per group instead of collecting lists? Explain the downstream collector.

level: middleimportance: must knowfreq 80%
basics
~10 s

Use the two-argument groupingBy(classifier, downstream). The downstream collector decides what each group becomes. For example groupingBy(Person::city, Collectors.counting()) gives Map<String, Long> of how many people are in each city.

open as a page

What is Collectors.partitioningBy and how does it differ from groupingBy?

level: middleimportance: should knowfreq 62%
basics
~20 s

partitioningBy splits elements into exactly two groups using a true/false test. The result is Map<Boolean, List<T>> with keys true and false. groupingBy can make any number of groups from any key; partitioningBy is the special two-bucket case.

open as a page

How do you produce a multi-level grouping such as Map<Country, Map<City, Long>>, and how do nested downstream collectors compose?

level: seniorimportance: should knowfreq 55%
basics
~10 s

Use groupingBy whose downstream is another groupingBy. The outer classifier picks the first key, the inner groupingBy groups within each outer group, and an innermost collector like counting() produces the leaf value.

open as a page

What guarantees does groupingBy make about result mutability, ordering, null handling, and parallel execution, and when would you reach for groupingByConcurrent?

level: principalimportance: nice to knowfreq 34%
basics
~20 s

By default groupingBy gives a plain HashMap with ArrayList values, in no guaranteed order, and a null classifier key throws. For parallel streams, groupingByConcurrent can build a ConcurrentHashMap directly, but only helps with an unordered, truly parallel stream.

open as a page

What is a downstream collector, and how do you use one to count or sum the elements within each group of a groupingBy?

level: juniorimportance: must knowfreq 72%
basics
~20 s

groupingBy can take a second collector that runs on each group. So instead of getting lists, you can count items per group with Collectors.counting() or add them up with summingInt(). The result is a Map from key to the computed value.

open as a page

How does Collectors.joining work, including its delimiter, prefix, and suffix overloads, and when is it preferable to manual string concatenation in a stream?

level: juniorimportance: should knowfreq 58%
basics
~20 s

Collectors.joining() concatenates the stream's CharSequence elements into one String. Overloads let you add a separator between elements, plus an optional prefix and suffix, e.g. joining(", ", "[", "]") turns names into "[a, b, c]". It only works on CharSequence elements, so map to String first.

open as a page

Explain Collectors.collectingAndThen and Collectors.teeing, and give a realistic use for each.

level: middleimportance: should knowfreq 48%
basics
~20 s

collectingAndThen wraps a collector and runs a final function on its result, e.g. collect into a List then make it unmodifiable. teeing (Java 12+) feeds the stream into two collectors at once and merges their two results with a combiner function, e.g. compute average as sum and count in one pass.

open as a page

What are the mapping, flatMapping, and filtering collector adapters, and how do they differ from the Stream operations of the same name?

level: middleimportance: should knowfreq 55%
basics
~20 s

They are adapter collectors that transform or filter elements before handing them to another (downstream) collector. mapping changes each element, flatMapping expands each into many, and filtering drops some. They are used inside groupingBy where you can't easily put a Stream.map/filter, because the grouping already routed the elements.

open as a page

How do you implement a custom Collector, and what are the roles of supplier, accumulator, combiner, finisher, and characteristics?

level: seniorimportance: should knowfreq 38%
basics
~20 s

A Collector has four functions plus a set of flags. The supplier makes a fresh mutable container, the accumulator adds one element into it, the combiner merges two containers (for parallel streams), the finisher turns the container into the final result, and characteristics tell the runtime if it can skip the finisher, run unordered, or run concurrently. You build one with Collector.of(...).

open as a page

Why do IntStream, LongStream, and DoubleStream exist when you already have Stream<Integer>? What problem do they solve?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A Stream<Integer> stores each number as a wrapped Integer object, which costs extra memory and time. Primitive streams (IntStream, LongStream, DoubleStream) hold raw int/long/double values directly, avoiding that wrapping and giving handy numeric operations like sum() and average().

open as a page

How do IntStream.range and IntStream.rangeClosed differ, and when would you use each?

level: juniorimportance: should knowfreq 55%
basics
~10 s

Both generate a stream of consecutive ints. range(start, end) excludes the end value; rangeClosed(start, end) includes it. So range(1, 5) gives 1,2,3,4 and rangeClosed(1, 5) gives 1,2,3,4,5.

open as a page

Explain boxed(), mapToObj, and the asLongStream()/asDoubleStream() conversions. How do you move between primitive streams and object streams?

level: middleimportance: should knowfreq 48%
basics
~20 s

boxed() turns an IntStream into a Stream<Integer> by wrapping each value, so you can collect into a List. mapToObj turns each primitive into any object you choose. asLongStream()/asDoubleStream() widen an IntStream to a LongStream/DoubleStream. To go from objects to primitives, use mapToInt/mapToLong/mapToDouble.

open as a page

What does summaryStatistics() return on a primitive stream, and why might you prefer it over calling sum(), min(), max(), and average() separately?

level: middleimportance: should knowfreq 50%
basics
~20 s

summaryStatistics() returns one object (e.g. IntSummaryStatistics) holding the count, sum, min, max, and average computed in a single pass over the stream. Calling sum(), min(), max(), average() separately would consume the stream multiple times — but a stream can only be consumed once.

open as a page

Why do IntStream.min(), average(), etc. return OptionalInt/OptionalDouble instead of Optional<Integer> or a plain value?

level: seniorimportance: should knowfreq 38%
basics
~20 s

A stream might be empty, so there may be no minimum or average to return. Optional represents 'maybe a value'. The primitive variants OptionalInt/OptionalDouble exist so the result stays unboxed — Optional<Integer> would force a wrapper object, defeating the point of using a primitive stream.

open as a page

What is a parallel stream in Java, and how do you create one from a collection?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A parallel stream splits the data into chunks and processes them on multiple threads at once, instead of one element at a time. You create one with collection.parallelStream() or by calling .parallel() on an existing stream.

open as a page

Where do parallel streams run their work by default, and why does the shared common ForkJoinPool matter?

level: middleimportance: must knowfreq 68%
basics
~20 s

By default parallel streams run on a single thread pool shared by the whole JVM, called the common ForkJoinPool. Its size is about the number of CPU cores minus one. Because it is shared, a slow or blocking task can starve everything else using it.

open as a page

What correctness requirements must your stream operations meet to be safe in parallel, and what are the classic hazards?

level: seniorimportance: must knowfreq 64%
basics
~20 s

Your lambdas must be stateless and thread-safe — they can't read or write shared mutable variables. Reductions must be associative so the order of combining partial results doesn't change the answer. Never mutate a shared collection or counter from a parallel stream; use a proper reduce/collect instead.

open as a page

How does a parallel stream divide its source for parallel processing, and why does the source's data structure affect performance?

level: seniorimportance: should knowfreq 55%
basics
~20 s

A parallel stream uses a Spliterator, whose trySplit() repeatedly cuts the source into halves so different threads can process them. Sources that split cheaply and evenly — arrays and ArrayList — parallelize well; LinkedList and Stream.iterate split poorly, so parallelism barely helps.

open as a page

How do you decide whether parallelism will actually pay off, and how do ordering-sensitive operations like findAny and forEach behave in parallel?

level: principalimportance: should knowfreq 50%
basics
~20 s

Parallelism pays off when there are many elements (N) and each costs real work (Q) — a big N×Q. For tiny data or cheap operations the overhead loses. In parallel, findAny may return any matching element (not the first), and forEach runs in no guaranteed order; use findFirst or forEachOrdered if order matters.

open as a page

What happens if you operate on a Java stream after it has already been consumed, and why is a stream single-use?

level: juniorimportance: must knowfreq 60%
basics
~10 s

A stream can only be used once. After a terminal operation like collect() or forEach() runs, the stream is consumed, and touching it again throws IllegalStateException. Create a fresh stream from the source instead.

open as a page

Why does modifying the source collection while streaming it cause a ConcurrentModificationException, and how do you restructure to avoid it?

level: middleimportance: must knowfreq 52%
basics
~20 s

Streams read the source lazily through an iterator that detects changes. If you add or remove elements from the source collection while the stream is running, you usually get a ConcurrentModificationException. Build a new collection from the stream instead of editing the old one.

open as a page

What goes wrong when Collectors.toMap encounters duplicate keys, and how do you handle it correctly?

level: middleimportance: must knowfreq 58%
basics
~10 s

The two-argument Collectors.toMap throws IllegalStateException ('Duplicate key') when two elements produce the same key. Use the three-argument version with a merge function to decide which value wins.

open as a page

Why prefer IntStream/LongStream/DoubleStream over Stream<Integer> for numeric work, and what is the cost of getting it wrong?

level: juniorimportance: should knowfreq 55%
basics
~10 s

Stream<Integer> wraps every number in an Integer object (boxing), which wastes memory and time. IntStream keeps raw int values, so it is faster and has handy methods like sum() and average().

open as a page

Why are side effects in stream operations (and especially using peek for mutation) discouraged, and what is peek actually for?

level: middleimportance: should knowfreq 50%
basics
~20 s

Streams expect each step to just transform data, not change outside state. peek is meant for debugging/logging only. Mutating in peek or map is fragile because steps are lazy and may be skipped, reordered, or run in parallel.

open as a page