Explain Codes LogoExplain Codes Logo

Why does Iterable<T> not provide stream() and parallelStream() methods?

java
stream-engineering
best-practices
performance
Alex KataevbyAlex Kataev·Dec 3, 2024
TLDR
// Convert Iterable to Stream // Because sometimes when life gives you Iterable, you make Streamonade Stream<T> stream = StreamSupport.stream(yourIterable.spliterator(), false);

Quick and easy - StreamSupport.stream(). Feed it your Iterable's spliterator() and tell it your plans for parallel processing with a boolean - false for sequential streams, and true for parallel ones. This is your StreamFactory turning Iterables into Streams without any changes to Iterable interface.

The design choice

The architects of Java left out stream() in Iterable after thorough consideration. It offered the freedom to return different kinds of streams based on actual use-cases, lending more flexibility in terms of functionality and performance improvements.

Perks of spliterator()

Versatile stream behavior

Iterable exposes the spliterator() method, giving developers a scalpel to fine-tune the behavior of the stream - e.g., choosing between parallel or sequential, ORDERED or NON-ORDERED characteristics.

Consensus from the expert group

In the expert group's discussion back in June 2013, the verdict was insightful: keep Iterable simple but empower developers to conjure up the desired Stream using StreamSupport and Spliterator.

Fulfills the needs of advanced users and library writers

Providing a direct handle to create a Stream from a Spliterator is beneficial to advanced users and library developers. It allows them to fine-tune stream behavior or create optimized stream sources.

Practical usage

Converting Iterable to Stream

In practice, transforming an Iterable to a Stream is a straightforward process. Here are some examples:

  • Sequential Stream:

    // Chill mode - One step at a time Stream<T> sequentialStream = StreamSupport.stream(yourIterable.spliterator(), false);
  • Parallel Stream:

    // Turbo mode - All boosters ignited Stream<T> parallelStream = StreamSupport.stream(yourIterable.spliterator(), true);

Keep in mind while streaming

When creating streams from an iterable, consider the characteristics of the original data source. A parallelStream on data that can't be divided efficiently may not yield any performance gains.

Upgrade your spliterator

Enhancing spliterator() in your custom Collection can improve its functionality. Implementing an optimal size estimate or additional characteristic flags can give performance boosts.

Stream support with AbstractCollection

AbstractCollection provides a leg-up with a default stream() method. So subclasses get to inherit stream support right out of the box.