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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import java.util.ArrayList; import java.util.Iterator; public class IteratorExample { public static void main(String[] args) { ArrayList<String> fruits = new ArrayList<>(); fruits.add("Apple"); fruits.add("Banana"); fruits.add("Cherry"); Iterator<String> iterator = fruits.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } } //Output Apple Banana Cherry |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class StreamExample { public static void main(String[] args) { List<String> fruits = new ArrayList<>(); fruits.add("Apple"); fruits.add("Banana"); fruits.add("Cherry"); fruits.add("Blueberry"); // Using Stream to filter and collect fruits starting with 'B' List<String> filteredFruits = fruits.stream() .filter(fruit -> fruit.startsWith("B")) .collect(Collectors.toList()); System.out.println(filteredFruits); } } //Output: [Banana, Blueberry] |
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. |