Course contents

Spliterator explained

Spliterator basics: traversal, splitting, size estimates, characteristics, late binding, fail-fast behavior, custom implementations and why splitting quality controls parallel stream performance.

PremiumGood to knowLesson11 min readSeniorReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: a deck you can split
  2. Traversal under the hood: tryAdvance and forEachRemaining
  3. Splitting and size: trySplit, estimateSize, exact size
  4. Characteristics: promises the stream can use
  5. Late binding and fail-fast behavior
  6. Advanced: writing a custom Spliterator
  7. Adapting iterators and unknown sizes
  8. Why poor splitting kills parallel performance
  9. How to say it in the interview

🧭 What is a Spliterator?

A Spliterator is an object that can traverse elements and, when possible, split itself into another spliterator over part of the remaining elements. The name means "splitable iterator," although the interface spells it Spliterator. Think of it as a stack of index cards that can either hand you the next card or tear the stack into two smaller stacks for two workers.

For this lesson, we'll focus on the methods and flags you need to understand streams: tryAdvance, forEachRemaining, trySplit, size estimates, characteristics, late binding, fail-fast behavior, and custom spliterators. We'll connect back to How a stream pipeline executes for how the source feeds sinks, and to Parallel streams: when they help and hurt for why poor splitting kills parallel performance.

Below the line (out of scope)

  • We will read and write spliterators for Java 21 stream sources.
  • We will not re-teach Iterator; see Iterator, ListIterator and every way to iterate for that angle.
  • We will discuss fail-fast as a best-effort bug detector, not as a synchronization guarantee.
  • We will keep custom examples small enough to compile in one file.

The 30-second answer

A Spliterator<T> is the stream source cursor. tryAdvance pushes one element to a Consumer and returns whether one existed; forEachRemaining drains the rest; trySplit tries to hand back another spliterator over part of the remaining data. estimateSize and getExactSizeIfKnown help the stream plan work, while characteristics such as ORDERED, SIZED, SUBSIZED, DISTINCT, SORTED, NONNULL, IMMUTABLE and CONCURRENT describe what the source promises. ArrayList splits by index ranges, usually in halves, which is great for parallel streams. Iterators and generated sources split poorly, so wrapping them with spliteratorUnknownSize is fine for traversal but weak for parallel performance.

What you’ll learn

  • Use tryAdvance and forEachRemaining to traverse elements one at a time or in bulk
  • Explain trySplit, estimateSize and getExactSizeIfKnown for parallel stream planning
  • Read characteristics such as ORDERED, SIZED, SUBSIZED, SORTED, DISTINCT, NONNULL, IMMUTABLE and CONCURRENT
  • Describe how an ArrayList spliterator splits ranges in half
  • Explain late-binding and fail-fast behavior without promising hard real-time detection
  • Create streams with StreamSupport.stream(spliterator, parallel) and adapt iterators with Spliterators.spliteratorUnknownSize
  • Connect poor splitting to poor parallel-stream performance

01Picture it first: a deck you can split

Imagine a deck of cards. An iterator can only say "next card, next card, next card." A spliterator can also cut the remaining deck and hand half to another worker, if it knows how.

That extra ability is why streams use spliterators as sources. Sequential streams need traversal; parallel streams need splitting.

Fig. 1

A spliterator can either advance one element to a consumer or split an indexed range into two smaller ranges

A spliterator can either advance one element to a consumer or split an indexed range into two smaller ranges

Notice the two paths. tryAdvance is about consuming elements. trySplit is about creating independent work.

02Traversal under the hood: tryAdvance and forEachRemaining

tryAdvance is the smallest traversal step. It accepts a Consumer, passes one element to it if available, and returns true. When there is no element left, it returns false.

Try it yourself first

Before reading the output, predict how many names are printed by the while loop and how many are printed by forEachRemaining.

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Splitting and size: trySplit, estimateSize, exact size
  • Characteristics: promises the stream can use
  • Late binding and fail-fast behavior
  • Advanced: writing a custom Spliterator
  • Adapting iterators and unknown sizes
  • Why poor splitting kills parallel performance
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicParallel streams & Spliterator: interview questions & scenarios
Further reading (5)