Iterators and Streams

Java is well-known for its rich API and extensive capabilities, and two important features that help in simplifying iteration and data manipulation are Iterators and Streams. Both provide efficient ways to work with collections, but they each serve different purposes and have unique characteristics.

Iterator

An Iterator in Java is a design pattern that provides a way to access elements of a collection sequentially, without exposing the underlying structure. It allows us to traverse through a collection, such as a list, set, or queue, and manipulate the elements during iteration.

Methods of an Iterator

  • hasNext(): Checks if there are more elements in the collection.
  • next(): Returns the next element in the iteration.
  • remove(): Removes the last element returned by the iterator (optional).

Example

When to Use Iterators

  • When you need to perform explicit removal of elements from a collection during iteration (via the remove() method).
  • When you are working with older versions of Java that don’t support Streams.
  • When you need fine-grained control over the iteration, such as modifying the iteration process itself.

Stream

A Stream in Java is part of the Java 8 java.util.stream package and represents a sequence of elements that can be processed in parallel or sequentially. It allows for more functional programming-style operations such as filtering, mapping, and reducing collections in a concise and readable manner.

Unlike iterators, streams are not data structures themselves but rather pipelines that allow operations to be applied to data sources like collections, arrays, or I/O channels.

  • Streams do not modify the underlying data structure.
  • They can be processed either sequentially or in parallel.
  • Streams are lazy, meaning the computation on data is only done when necessary.

Methods of a Stream

  • filter(): Filters elements based on a condition.
  • map(): Transforms each element using a function.
  • forEach(): Performs an action on each element.
  • reduce(): Combines elements into a single result (e.g., sum, multiplication).
  • collect(): Collects the result into a different form, like a list or set.

Example

When to Use Streams

  • When you want to process data in a functional style—using operations like map(), filter(), reduce(), etc.
  • When you need to process data in parallel for performance improvements.
  • When you’re performing complex transformations and aggregations that are easier to express in a declarative manner.

Iterator vs Stream in Java

Feature Iterator Stream
Purpose Sequential access to elements in a collection. Functional-style processing of sequences of elements.
Stateful/Stateless Stateful (tracks current position in the collection). Stateless (generates a new stream on each operation).
Parallel Processing No inherent parallelism support. Can be processed in parallel using parallelStream().
Modification Allows removing elements via remove() during iteration. Does not modify the source collection.
Performance Can be more efficient for simple iterations. Optimized for complex operations like filtering, mapping, and reducing.