import java.util.Iterator;Java Iterator and ListIterator: Safe Collection Traversal and Modification
Direct Answer & Core Concept
Java collections such as ArrayList, LinkedList, HashSet, and LinkedHashSet store multiple elements, but sometimes you need to process those elements one by one.
Java provides the Iterator interface for traversing collections safely and consistently. For lists, Java also provides ListIterator, which supports forward and backward traversal and allows additional list modifications during iteration.
Understanding these interfaces is important when you need to remove or modify collection elements while iterating.
Detailed Explanation & Mechanics
What Is an Iterator in Java?
An Iterator is an object used to traverse elements of a collection one at a time.
It is available through the java.util package:
A basic example:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println(name);
}
}
}Output:
AmitPriyaRahulThe iterator moves through the collection one element at a time.
Why Use Iterator?
You could use an enhanced for loop:
for (String name : names) {
System.out.println(name);
}But Iterator becomes particularly useful when you need to remove elements safely during traversal.
For example:
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Rahul")) {
iterator.remove();
}
}The iterator's remove() method removes the last element returned by next().
Iterator Interface
The main methods of Iterator are:
| Method | Purpose |
|---|---|
hasNext() | Checks whether another element exists |
next() | Returns the next element |
remove() | Removes the last element returned by next() |
forEachRemaining() | Performs an action on remaining elements |
The most frequently used methods are:
hasNext()next()remove()hasNext()
hasNext() checks whether another element is available.
Example:
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}It returns:
truewhen another element is available and:
falsewhen traversal has reached the end.
next()
The next() method returns the next element.
Iterator<String> iterator = names.iterator();
String first = iterator.next();
System.out.println(first);If no element remains and next() is called, the iterator can throw:
NoSuchElementExceptionTherefore, the normal pattern is:
while (iterator.hasNext()) {
System.out.println(iterator.next());
}remove()
Iterator.remove() removes the last element returned by next().
Example:
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
int number = iterator.next();
if (number > 20) {
iterator.remove();
}
}System.out.println(numbers);Output:
[10, 20]This is a safe way to remove elements during iterator traversal.
Why Not Remove Directly from the Collection?
Consider this example:
for (Integer number : numbers) {
if (number > 20) {
numbers.remove(number);
}
}Modifying many collections structurally while using an iterator-backed loop can cause:
ConcurrentModificationExceptionInstead, use the iterator's own remove() method:
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
if (number > 20) {
iterator.remove();
}
}This tells the iterator that the removal is intentional and keeps its traversal state synchronized with the collection.
Iterator and ConcurrentModificationException
Many standard Java collections use a fail-fast iterator.
For example:
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Priya")) {
names.remove(name);
}
}This can result in:
ConcurrentModificationExceptionThe problem is that the collection was structurally modified directly instead of through the iterator.
Use:
iterator.remove();when removal is required during iterator traversal.
Fail-fast behavior is a best-effort safety mechanism, not a thread-safety guarantee.
Iterator with ArrayList
Iterator works with ArrayList.
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Output:
JavaPythonC++Iterator with LinkedList
Iterator also works with LinkedList.
List<String> languages = new LinkedList<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}The same iterator interface can be used even though the underlying collection implementation is different.
Iterator with HashSet
Iterator is not limited to lists.
You can iterate through a HashSet:
Set<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());
}Remember that HashSet does not guarantee a predictable iteration order.
Therefore, do not expect the elements to appear in insertion order.
Iterator with LinkedHashSet
LinkedHashSet also provides an iterator.
Set<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());
}Because LinkedHashSet maintains insertion order, its iterator normally traverses the elements in that order.
Iterator vs Enhanced for Loop
Both can be used for traversal.
Enhanced for loop
for (String name : names) {
System.out.println(name);
}Iterator
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}The enhanced for loop is usually simpler for basic reading.
Iterator is particularly useful when you need explicit iterator operations such as:
iterator.remove();What Is ListIterator?
ListIterator is a specialized iterator for lists.
It extends the capabilities of Iterator and supports:
forward traversal
backward traversal
adding elements
replacing elements
removing elements
checking previous elements
obtaining indexes
It is available through:
import java.util.ListIterator;ListIterator works with List implementations such as:
ArrayListLinkedListBasic ListIterator Example
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}Output:
AmitPriyaRahulListIterator Can Move Backward
This is one of the biggest differences between Iterator and ListIterator.
After moving forward, you can move backward using:
hasPrevious()previous()Example:
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
iterator.next();
}while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}Output:
RahulPriyaAmitListIterator Methods
Important ListIterator methods include:
| Method | Purpose |
|---|---|
hasNext() | Checks for a next element |
next() | Returns the next element |
hasPrevious() | Checks for a previous element |
previous() | Returns the previous element |
nextIndex() | Returns the index of the next element |
previousIndex() | Returns the index of the previous element |
remove() | Removes the last returned element |
set() | Replaces the last returned element |
add() | Inserts an element at the iterator's current position |
hasPrevious()
hasPrevious() checks whether an element exists before the current iterator position.
Example:
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
iterator.next();
}while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}The second loop travels from the end toward the beginning.
previous()
previous() returns the previous element and moves the iterator backward.
Example:
ListIterator<String> iterator = names.listIterator();
iterator.next();
iterator.next();
System.out.println(iterator.previous());The iterator moves back one position and returns the element before its current cursor position.
ListIterator Index Methods
ListIterator provides:
nextIndex()previousIndex()Example:
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
ListIterator<String> iterator = names.listIterator();
System.out.println(iterator.nextIndex());
System.out.println(iterator.previousIndex());Initially, the cursor is before the first element.
The output is:
0-1After calling:
iterator.next();the cursor moves forward.
Using set() with ListIterator
ListIterator can replace the last element returned by next() or previous() using set().
Example:
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Priya")) {
iterator.set("Priya Sharma");
}
}System.out.println(names);Output:
[Amit, Priya Sharma, Rahul]The existing element is replaced.
Using add() with ListIterator
ListIterator can also insert an element.
Example:
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Rahul");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Amit")) {
iterator.add("Priya");
}
}System.out.println(names);Output:
[Amit, Priya, Rahul]The new element is inserted at the iterator's current position.
Using remove() with ListIterator
You can also remove the last element returned by next() or previous().
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Priya")) {
iterator.remove();
}
}System.out.println(names);Output:
[Amit, Rahul]Iterator vs ListIterator
The differences are important:
| Feature | Iterator | ListIterator |
|---|---|---|
| Works with collections generally | Yes | No, list only |
| Forward traversal | Yes | Yes |
| Backward traversal | No | Yes |
remove() | Yes | Yes |
set() | No | Yes |
add() | No | Yes |
nextIndex() | No | Yes |
previousIndex() | No | Yes |
A simple rule is:
Iterator→ General collection traversalListIterator→ Advanced List traversal and modificationStarting ListIterator at a Specific Position
You can create a ListIterator starting at a particular index.
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
names.add("Suman");
ListIterator<String> iterator = names.listIterator(2);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Output:
RahulSumanThe iterator starts before the element at index 2.
Traversing a List in Both Directions
One powerful feature of ListIterator is bidirectional traversal.
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Priya");
names.add("Rahul");
ListIterator<String> iterator = names.listIterator();
System.out.println("Forward:");
while (iterator.hasNext()) {
System.out.println(iterator.next());
}System.out.println("Backward:");
while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}Output:
Forward:AmitPriyaRahulBackward:RahulPriyaAmitSafe Removal with Iterator
Suppose you want to remove all even numbers.
A direct removal approach can be problematic:
for (Integer number : numbers) {
if (number % 2 == 0) {
numbers.remove(number);
}
}Instead:
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
if (number % 2 == 0) {
iterator.remove();
}
}This is the traditional iterator-based pattern for safe removal during traversal.
Modern Alternative: removeIf()
For a simple filtering operation, modern Java often provides an even simpler solution:
numbers.removeIf(number -> number % 2 == 0);This can be preferable when the task is simply:
Remove every element matching this condition.
Use Iterator when you specifically need iterator-based traversal or more control over the traversal process.
Modifying Values During ListIterator Traversal
Suppose you want to convert every name to uppercase.
List<String> names = new ArrayList<>();
names.add("amit");
names.add("priya");
names.add("rahul");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
iterator.set(name.toUpperCase());
}System.out.println(names);Output:
[AMIT, PRIYA, RAHUL]set() replaces the last element returned by the iterator.
Iterator Cursor Concept
An iterator can be imagined as a cursor positioned between elements.
For:
[A, B, C]the cursor starts conceptually here:
| A | B | C |^cursorAfter:
iterator.next();it moves:
| A | B | C | ^ cursorAfter another next():
| A | B | C | ^ cursorThis cursor model is especially important for understanding ListIterator.
Understanding ListIterator Cursor
Suppose the list is:
[A, B, C]Initially:
| A | B | C |^After next():
| A | B | C | ^After another next():
| A | B | C | ^Calling previous() moves the cursor backward:
| A | B | C | ^This is why ListIterator can move in both directions.
Important Iterator Rule for remove()
The remove() operation has a specific relationship with next() or previous().
You normally need to call:
next()or:
previous()before calling:
remove()Calling remove() repeatedly without another appropriate traversal operation can cause:
IllegalStateExceptionFor example:
Iterator<String> iterator = names.iterator();
iterator.remove();is invalid because the iterator has not yet returned an element.
Important ListIterator Rule for set()
set() also operates on the element most recently returned by:
next()or:
previous()For example:
ListIterator<String> iterator = names.listIterator();
iterator.next();
iterator.set("New Name");is valid.
But calling set() before returning an element can cause:
IllegalStateExceptionCertain iterator operations such as add() also affect when set() or remove() can next be used, so the iterator's modification rules should be followed carefully.
Iterator and UnsupportedOperationException
Not every collection supports modification through its iterator.
For example, an iterator obtained from an unmodifiable collection may not support:
iterator.remove();In such cases, a modification attempt can throw:
UnsupportedOperationExceptionThis is different from ConcurrentModificationException.
UnsupportedOperationExceptionmeans the operation is not supported.ConcurrentModificationExceptioncan indicate an unsupported structural modification was detected during fail-fast traversal.
Iterator with Map
A Map is not a Collection, so you do not directly call:
map.iterator();Instead, you obtain an iterator from one of its collection views.
For example:
Map<Integer, String> users = new HashMap<>();
users.put(101, "Amit");
users.put(102, "Priya");
Iterator<Map.Entry<Integer, String>> iterator = users.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
System.out.println( entry.getKey() + " = " + entry.getValue());
}This is the standard way to iterate through map entries using an iterator.
Removing Map Entries with Iterator
You can safely remove map entries through the iterator obtained from entrySet():
Iterator<Map.Entry<Integer, String>> iterator = users.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
if (entry.getKey() == 101) {
iterator.remove();
}
}The corresponding mapping is removed from the map.
Iterator vs Stream
Java Streams provide another way to process collections:
names.stream() .filter(name -> name.startsWith("A")) .forEach(System.out::println);Streams are excellent for declarative data processing.
Iterators are useful when you need explicit traversal control, especially when performing iterator-supported modifications.
A simple distinction:
Iterator→ Explicit traversalStream→ Declarative processing pipelineThey solve related but different problems.
Iterator in Real-World Applications
Iterators can be useful when:
removing matching elements while traversing
processing collections incrementally
working with different collection implementations through a common API
traversing sets without relying on indexes
iterating over map entries
implementing collection-processing logic
needing explicit traversal state
ListIterator is particularly useful for:
editing lists while traversing
moving forward and backward
inserting elements
replacing elements
navigating by list position
Complete Iterator Example
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(15);
numbers.add(20);
numbers.add(25);
numbers.add(30);
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
if (number % 2 == 0) {
iterator.remove();
}
} System.out.println(numbers);
}
}Output:
[15, 25]The iterator safely removes the even numbers.
Complete ListIterator Example
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("amit");
names.add("priya");
names.add("rahul");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
iterator.set(name.toUpperCase());
} System.out.println("Forward:");
System.out.println(names);
System.out.println("Backward:");
while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}
}
}Output:
Forward:[AMIT, PRIYA, RAHUL]Backward:RAHULPRIYAAMITThis example demonstrates both modification and backward traversal.
Common Mistakes with Iterator
Mistake 1: Calling next() Without Checking hasNext()
Avoid:
while (true) {
System.out.println(iterator.next());
}This can eventually throw NoSuchElementException.
Prefer:
while (iterator.hasNext()) {
System.out.println(iterator.next());
}Mistake 2: Removing Directly from the Collection
Avoid modifying the collection directly during iterator traversal:
for (String name : names) {
names.remove(name);
}Use:
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (condition) {
iterator.remove();
}
}Mistake 3: Expecting Iterator to Move Backward
A normal Iterator only supports forward traversal.
If backward traversal is required, use:
ListIteratorwith a List.
Mistake 4: Using ListIterator with a Set
ListIterator is designed for List implementations.
You cannot obtain a ListIterator directly from a HashSet.
Use:
Iteratorfor sets.
Mistake 5: Assuming Iterator Makes Collections Thread-Safe
An iterator does not automatically make a collection safe for concurrent access.
Thread safety is a separate concern.
Iterator vs ListIterator: Easy Memory Trick
Remember:
Iterator↓ForwardRemoveListIterator↓ForwardBackwardRemoveReplaceAddIndexesThis makes the difference easy to remember during interviews and exams.
Frequently Asked Questions
What is Iterator in Java?
Iterator is an interface used to traverse elements of a collection sequentially.
What does hasNext() do?
It checks whether another element is available during forward traversal.
What does next() do?
It returns the next element and advances the iterator.
Can Iterator remove elements?
Yes, through Iterator.remove(), when the underlying collection and iterator support removal.
What is ListIterator?
ListIterator is an advanced iterator designed for lists. It supports forward and backward traversal and additional operations such as add() and set().
Can ListIterator move backward?
Yes. Use:
hasPrevious()previous()Can Iterator modify elements?
A normal Iterator provides remove() but does not provide set() or add(). ListIterator provides those additional list modification operations.
Does Iterator work with HashSet?
Yes.
Does ListIterator work with HashSet?
No. ListIterator is for lists.
What is ConcurrentModificationException?
It is commonly associated with fail-fast iterators detecting structural modification of a collection outside the iterator's supported modification mechanism while traversal is in progress.
Is Iterator thread-safe?
No. An iterator itself does not make a collection thread-safe.
Graphics and Design Ideas
Graphic 1: Iterator Forward Traversal
Show:
[A] →[B] →[C] →[D] ↑IteratorAnimate the iterator moving from left to right.
Graphic 2: ListIterator Bidirectional Traversal
Show:
Forward →[A] ↔[B] ↔[C] ↔[D] ← BackwardUse two arrows to visually explain the difference between Iterator and ListIterator.
Graphic 3: Safe Removal
Show:
Collection↓Iterator↓next()↓Check condition↓remove()↓Collection updatedThis clearly demonstrates why iterator.remove() is safer than directly changing the collection during traversal.
Graphic 4: Iterator vs ListIterator
Create a side-by-side comparison:
Iterator ListIteratorForward ✓ Forward ✓Backward ✗ Backward ✓Remove ✓ Remove ✓Set ✗ Set ✓Add ✗ Add ✓Index ✗ Index ✓This can work well as the main featured image for the tutorial.
Runnable Code Example: Java Iterator and ListIterator
Java 17+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorDemo {
public static void main(String[] args) {
List<String> items = new ArrayList<>(List.of("Java", "Deprecated", "Kotlin", "Deprecated"));
// Safe element removal using Iterator
Iterator<String> it = items.iterator();
while (it.hasNext()) {
String current = it.next();
if ("Deprecated".equals(current)) {
it.remove();
// Safe removal
}
} System.out.println("Cleaned List: " + items);
}
}