Java Collections Framework - Iterator
An Iterator in Java is an object used to traverse or iterate through the elements of a collection one by one.
It provides a common way to access elements from collections such as:
- ArrayList
- LinkedList
- HashSet
- LinkedHashSet
- TreeSet
- and many other collection classes
The Iterator interface is available in the java.util package.
import java.util.Iterator;Why do we use Iterator?
Different collection classes may store their elements differently.
For example:
- ArrayList stores elements using indexes.
- HashSet does not provide index-based access.
- TreeSet maintains elements according to their ordering.
Instead of learning a different traversal mechanism for every collection, Java provides the Iterator interface.
It provides a common way to move through collection elements.
Basic Example
Consider an ArrayList:
import java.util.ArrayList;
import java.util.Iterator;
public class HelloWorld {
public static void main(String[] args) {
ArrayList<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
System.out.println(language);
}
}
}Output
Java
Python
C++How Iterator Works
The basic process is:
Collection
↓
iterator()
↓
Iterator object
↓
hasNext()
↓
next()
↓
Next elementFor example:
Iterator<String> iterator = languages.iterator();This creates an iterator for the collection.
Then:
iterator.hasNext()checks whether another element is available.
If an element exists:
iterator.next()returns the next element.
Important Iterator Methods
The Iterator interface mainly provides the following methods:
| Method | Purpose |
|---|---|
| hasNext() | Checks whether another element exists |
| next() | Returns the next element |
| remove() | Removes the last element returned by the iterator |
| forEachRemaining() | Performs an action on remaining elements |
Let's understand them one by one.
1. hasNext()
The hasNext() method checks whether there is another element available.
It returns:
trueif another element exists.
Otherwise, it returns:
falseExample
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}The loop continues as long as another element is available.
Why is hasNext() important?
Calling next() when there are no more elements can result in a NoSuchElementException.
Therefore, it is common to check:
iterator.hasNext()before calling:
iterator.next()2. next()
The next() method returns the next element from the collection.
Example
Iterator<String> iterator = languages.iterator();
System.out.println(iterator.next());
System.out.println(iterator.next());If the collection contains:
Java
Python
C++the output will be:
Java
PythonThe iterator maintains its current position as it moves through the collection.
3. remove()
The remove() method removes the last element returned by the iterator, if that iterator supports removal. It is an optional operation; unsupported removal throws UnsupportedOperationException.
Example
ArrayList<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
if (language.equals("Python")) {
iterator.remove();
}
}
System.out.println(languages);Output
[Java, C++]Why use Iterator.remove()?
Removing elements directly from a collection while using an iterator can cause a ConcurrentModificationException for many collection implementations.
For example, this pattern should generally be avoided:
for (String language : languages) {
if (language.equals("Python")) {
languages.remove(language);
}
}Instead, use the iterator's remove() method when performing removal during iterator traversal:
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
if (language.equals("Python")) {
iterator.remove();
}
}Important Rule for remove()
remove() removes the element returned by the most recent next() call.
For iterators supporting removal, calling remove() before next() is invalid. Calling it twice after a single next() call is also invalid.
For example:
Iterator<String> iterator = languages.iterator();
iterator.remove();This can result in an IllegalStateException.
4. forEachRemaining()
The forEachRemaining() method performs an action on all remaining elements.
Example
Iterator<String> iterator = languages.iterator();
iterator.forEachRemaining(
language -> System.out.println(language)
);This processes the elements that have not yet been consumed by the iterator.
Iterator with ArrayList
Example
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Output
10
20
30
40Iterator with HashSet
One important advantage of Iterator is that it can also be used with collections that do not provide index-based access.
For example:
HashSet<String> languages = new HashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}This is useful because HashSet does not provide methods such as:
get(0)
get(1)
get(2)like an ArrayList.
Iterator with LinkedHashSet
LinkedHashSet<String> languages =
new LinkedHashSet<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
Iterator<String> iterator =
languages.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Since LinkedHashSet maintains insertion order, iteration follows that order.
Iterator with TreeSet
Iterator can also be used with TreeSet.
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(30);
numbers.add(10);
numbers.add(20);
Iterator<Integer> iterator =
numbers.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Output
10
20
30The TreeSet maintains its sorted ordering, so the iterator encounters elements according to that ordering.
Iterator with Map
There is an important difference between Collection and Map.
A Map does not directly provide an iterator() method.
For example, this is not valid:
Map<Integer, String> map = new HashMap<>();
Iterator<Integer> iterator = map.iterator();Instead, we can obtain an iterator from the Map's collection views.
Iterating Through Map Entries
Map<Integer, String> map = new HashMap<>();
map.put(101, "Ashish");
map.put(102, "Rahul");
map.put(103, "Priya");
Iterator<Map.Entry<Integer, String>> iterator =
map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry =
iterator.next();
System.out.println(
entry.getKey() + " -> " + entry.getValue()
);
}Iterating Through Map Keys
Iterator<Integer> iterator =
map.keySet().iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Iterating Through Map Values
Iterator<String> iterator =
map.values().iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Iterator vs Enhanced for Loop
Java also provides the enhanced for loop:
for (String language : languages) {
System.out.println(language);
}This is often simpler than using an iterator explicitly.
The enhanced for loop internally uses an iterator for Iterable collections.
When should we use Iterator?
An explicit Iterator is particularly useful when:
- We need to remove elements during traversal.
- We need direct control over traversal.
- We are working with collections that do not support index-based access.
- We need iterator-specific behavior.
For simple traversal, the enhanced for loop is often easier to read.
Iterator vs ListIterator
Java also provides another interface called ListIterator.
The main difference is that Iterator generally moves in one direction, while ListIterator provides additional functionality for lists.
| Iterator | ListIterator |
|---|---|
| Works with collections through iterator() | Designed specifically for List |
| Mainly moves forward | Can move forward and backward |
| hasNext() | hasNext() and hasPrevious() |
| next() | next() and previous() |
| Can remove | Can remove |
| Cannot directly add elements | Can add elements |
| Cannot directly replace elements | Can replace elements using set() |
Example
ListIterator<String> iterator =
languages.listIterator();ListIterator is useful when working specifically with lists and needing bidirectional traversal.
Iterator and ConcurrentModificationException
A common problem when modifying a collection during iteration is:
ConcurrentModificationExceptionFor example:
for (String language : languages) {
if (language.equals("Python")) {
languages.remove(language);
}
}This can cause a ConcurrentModificationException.
A safer approach for iterator-based removal is:
Iterator<String> iterator =
languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
if (language.equals("Python")) {
iterator.remove();
}
}Important Note
Iterator.remove() is the iterator-supported way to remove the element most recently returned by that iterator.
However, the exact behavior of concurrent modifications can depend on the collection implementation. Many standard Java collections use fail-fast iterators, which detect certain structural modifications and may throw ConcurrentModificationException.
Complete Example
import java.util.ArrayList;
import java.util.Iterator;
public class HelloWorld {
public static void main(String[] args) {
ArrayList<String> languages =
new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
languages.add("JavaScript");
Iterator<String> iterator =
languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
if (language.equals("Python")) {
iterator.remove();
}
}
System.out.println(languages);
}
}Output
[Java, C++, JavaScript]Advantages of Iterator
1. Common Traversal Mechanism
Iterator provides a standard way to traverse many different collection types.
2. Works Without Indexes
It can be used with collections such as HashSet that do not provide index-based access.
3. Safe Removal During Traversal
Its remove() method provides a supported way to remove the last returned element.
4. Simple Traversal
The combination of:
hasNext()and:
next()makes collection traversal straightforward.
Limitations of Iterator
- It generally moves only in the forward direction.
- It does not provide index-based access.
- It cannot directly add an element.
- It cannot directly replace an element.
For lists requiring forward and backward traversal, ListIterator is more suitable.
Important Points
- Iterator is an interface in java.util.
- It is used to traverse collection elements.
- hasNext() checks whether another element exists.
- next() returns the next element.
- remove() removes the last element returned by next().
- forEachRemaining() processes remaining elements.
- Iterator can be used with lists, sets, and collection views of maps.
- A Map itself does not directly provide an iterator.
- entrySet(), keySet(), or values() can be used to obtain an iterator from a Map.
- ListIterator provides additional functionality for lists.
- Modifying a collection directly while iterating can result in ConcurrentModificationException.
- For iterator-based removal, use Iterator.remove().
Key Takeaway
An Iterator provides a standard way to traverse elements of a collection one by one.
The most commonly used pattern is:
Iterator<String> iterator =
collection.iterator();
while (iterator.hasNext()) {
String value = iterator.next();
System.out.println(value);
}When elements need to be removed during traversal:
if (condition) {
iterator.remove();
}Understanding Iterator is important because it forms one of the fundamental mechanisms for traversing Java collections.
See you in next page....🙂