Using Iterator and ListIterator in Java
Course: Core Java Training
Topic: Using Iterator and ListIterator
Course Link: Core Java Training Course
Demo Link: Register for a Course Demo
Website: JustAcademy
1. Introduction to Iterator and ListIterator
Java provides Iterator and ListIterator interfaces to traverse elements stored in collections. Traversal means accessing elements one by one without needing to know the internal implementation of the collection.
These interfaces are part of the Java Collections Framework and are useful when processing, searching, removing, or updating elements in supported collections.
- Iterator: Supports forward traversal and provides a controlled way to remove the last element returned by the iterator when removal is supported.
- ListIterator: Extends Iterator and supports forward and backward traversal, element replacement, and insertion when the underlying list supports these operations.
Learning Objectives
- Understand the purpose of iterators in Java.
- Learn how to create and use an Iterator.
- Understand the methods available in the Iterator interface.
- Learn how ListIterator differs from Iterator.
- Traverse lists in both forward and backward directions.
- Add, replace, and remove list elements during iteration.
- Understand common iterator errors and best practices.
2. What Is an Iterator in Java?
An Iterator is an interface in the java.util package that provides a standard way to traverse elements in a collection. It is commonly used with collections such as ArrayList, LinkedList, HashSet, and other implementations of the Collection interface.
An iterator maintains a traversal position and provides methods to determine whether more elements are available and retrieve the next element.
Key Characteristics of Iterator
- Traverses elements in the forward direction.
- Uses
hasNext() to check whether another element is available.
- Uses
next() to retrieve the next element.
- Can remove the last returned element through
remove() when the operation is supported.
- Supports
forEachRemaining() for processing remaining elements.
- Can be used with many collection types, including lists and sets.
- Does not provide indexed access or backward traversal.
3. Syntax for Creating an Iterator
The iterator() method of a collection returns an Iterator for traversing its elements.
Iterator<DataType> iteratorName = collection.iterator();
For example:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
System.out.println(language);
}
}
}
Output:
Java
Python
JavaScript
Explanation:
ArrayList stores the language names.
iterator() creates an iterator for the list.
hasNext() checks whether an element remains.
next() retrieves the next element and advances the iterator.
- The loop ends when there are no more elements.
4. Important Methods of the Iterator Interface
| Method |
Description |
Example |
hasNext() |
Returns true if another element is available. |
iterator.hasNext() |
next() |
Returns the next element and advances the iterator. |
iterator.next() |
remove() |
Removes the last element returned by next(), if supported. |
iterator.remove() |
forEachRemaining(action) |
Processes the remaining elements using the supplied action. |
iterator.forEachRemaining(System.out::println) |
5. Understanding hasNext() and next()
The two most frequently used Iterator methods are hasNext() and next().
5.1 hasNext()
The hasNext() method returns true if another element is available. It does not advance the iterator.
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
Iterator<Integer> iterator = numbers.iterator();
System.out.println(iterator.hasNext());
Output:
true
5.2 next()
The next() method retrieves the next element and advances the iterator. Calling next() when no elements remain causes a NoSuchElementException.
System.out.println(iterator.next());
System.out.println(iterator.next());
Output:
10
20
Always use hasNext() to check whether an element remains before calling next() in a typical traversal loop.
6. Removing Elements Using Iterator
The remove() method removes the last element returned by the iterator's next() method. This is useful when filtering a collection during traversal.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorRemoveExample {
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()) {
int number = iterator.next();
if (number % 2 != 0) {
iterator.remove();
}
}
System.out.println(numbers);
}
}
Output:
[10, 20, 30]
Explanation: The iterator examines each number and removes odd values through iterator.remove(). This avoids directly modifying the list's structure during the traversal.
Important Rules for remove()
- Call
next() before calling remove().
- Only one removal is permitted for each successful call to
next().
- Calling
remove() without a valid preceding next() call can cause an IllegalStateException.
- Some collections or iterators do not support removal and may throw
UnsupportedOperationException.
7. What Is ListIterator in Java?
ListIterator is an interface in the java.util package that extends Iterator. It is specifically designed for lists and provides additional capabilities beyond ordinary forward traversal.
Unlike Iterator, ListIterator can move both forward and backward through a list. It also provides methods to insert new elements, replace the last returned element, and obtain the indexes associated with its cursor position.
Key Characteristics of ListIterator
- Supports forward traversal using
hasNext() and next().
- Supports backward traversal using
hasPrevious() and previous().
- Supports element replacement through
set(), when supported.
- Supports element insertion through
add(), when supported.
- Supports removal through
remove(), when supported.
- Provides
nextIndex() and previousIndex().
- Can be obtained from a List using
listIterator() or listIterator(index).
8. Syntax for Creating a ListIterator
A ListIterator is obtained from a list by calling the listIterator() method.
ListIterator<DataType> iteratorName = list.listIterator();
To start traversal at a particular position, pass a valid index:
ListIterator<DataType> iteratorName = list.listIterator(index);
The index must be between zero and the list's size, inclusive. If the index is equal to the list size, the iterator starts at the end.
Example
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Mango");
ListIterator<String> iterator = fruits.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
Output:
Apple
Banana
Mango
9. Important Methods of the ListIterator Interface
| Method |
Description |
hasNext() |
Checks whether an element is available in the forward direction. |
next() |
Returns the next element and moves forward. |
hasPrevious() |
Checks whether an element is available in the backward direction. |
previous() |
Returns the previous element and moves backward. |
nextIndex() |
Returns the index of the element that a subsequent next() call would return. |
previousIndex() |
Returns the index of the element that a subsequent previous() call would return. |
add(element) |
Inserts an element at the iterator's current cursor position. |
set(element) |
Replaces the last element returned by next() or previous(). |
remove() |
Removes the last element returned by next() or previous(). |
10. Forward Traversal Using ListIterator
Forward traversal processes elements from the beginning of the list toward the end. It works similarly to ordinary Iterator traversal.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ForwardTraversal {
public static void main(String[] args) {
List<String> subjects = new ArrayList<>();
subjects.add("Java");
subjects.add("SQL");
subjects.add("Python");
ListIterator<String> iterator = subjects.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
Output:
Java
SQL
Python
11. Backward Traversal Using ListIterator
ListIterator allows a list to be traversed in reverse order. To move backward from the end, first move the cursor to the end or finish a forward traversal.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class BackwardTraversal {
public static void main(String[] args) {
List<String> colors = new ArrayList<>();
colors.add("Red");
colors.add("Green");
colors.add("Blue");
ListIterator<String> iterator =
colors.listIterator(colors.size());
while (iterator.hasPrevious()) {
System.out.println(iterator.previous());
}
}
}
Output:
Blue
Green
Red
Explanation: Passing colors.size() starts the iterator at the end of the list. Each call to previous() returns the preceding element and moves the cursor backward.
12. Understanding the ListIterator Cursor
A ListIterator does not point directly at a current element. Its cursor is positioned between list elements. A list with three elements has four possible cursor positions.
Elements: [A] [B] [C]
Positions: ^ ^ ^ ^
At the start of the list, next() returns the first element. At the end, previous() returns the last element.
nextIndex() returns the index of the element that would be returned by the next call to next().
previousIndex() returns the index of the element that would be returned by the next call to previous().
- At the beginning,
previousIndex() returns -1.
- At the end,
nextIndex() returns the list size.
Example
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class IteratorIndexExample {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
ListIterator<String> iterator = items.listIterator();
System.out.println(iterator.nextIndex());
System.out.println(iterator.previousIndex());
iterator.next();
System.out.println(iterator.nextIndex());
System.out.println(iterator.previousIndex());
}
}
Output:
0
-1
1
0
13. Adding Elements Using ListIterator
The add() method inserts a new element at the cursor position. The inserted element appears after the element previously returned by previous() and before the element that would be returned by next().
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorAddExample {
public static void main(String[] args) {
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
ListIterator<String> iterator = languages.listIterator();
iterator.next();
iterator.add("SQL");
System.out.println(languages);
}
}
Output:
[Java, SQL, Python]
The iterator first moves past Java, then inserts SQL at its cursor position. The list becomes [Java, SQL, Python].
14. Replacing Elements Using ListIterator
The set() method replaces the last element returned by next() or previous(). It cannot be used until one of these methods has returned an element, and it must not follow an intervening add() or remove() operation.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorSetExample {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Amit");
names.add("Neha");
names.add("Ravi");
ListIterator<String> iterator = names.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Neha")) {
iterator.set("Priya");
}
}
System.out.println(names);
}
}
Output:
[Amit, Priya, Ravi]
This technique is useful when an existing list element must be updated while traversing the list.
15. Removing Elements Using ListIterator
ListIterator also supports remove(). It removes the last element returned by either next() or previous(), provided the list supports removal and the iterator is in a valid state.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorRemoveExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
ListIterator<Integer> iterator = numbers.listIterator();
while (iterator.hasNext()) {
int number = iterator.next();
if (number == 30) {
iterator.remove();
}
}
System.out.println(numbers);
}
}
Output:
[10, 20, 40]
16. Starting ListIterator at a Specific Index
The overloaded listIterator(index) method lets you begin traversal from a specific position in the list. The index must be between zero and the list size, inclusive.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class StartAtIndexExample {
public static void main(String[] args) {
List<String> cities = new ArrayList<>();
cities.add("Mumbai");
cities.add("Pune");
cities.add("Delhi");
cities.add("Chennai");
ListIterator<String> iterator = cities.listIterator(2);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
Output:
Delhi
Chennai
Because the starting index is 2, the first call to next() returns the element at index 2, which is Delhi.
17. Difference Between Iterator and ListIterator
| Feature |
Iterator |
ListIterator |
| Interface relationship |
Basic traversal interface |
Extends Iterator |
| Supported collections |
Many collection types, including lists and sets |
Lists only |
| Traversal direction |
Forward only |
Forward and backward |
| Read next element |
Yes, using next() |
Yes, using next() |
| Read previous element |
No |
Yes, using previous() |
| Remove elements |
Yes, if supported |
Yes, if supported |
| Add elements during iteration |
No add() method |
Yes, using add(), if supported |
| Replace the last returned element |
No set() method |
Yes, using set(), if supported |
| Index information |
Not provided |
nextIndex() and previousIndex() |
| Starting position |
Normally starts at the beginning |
Can start at a specified valid index |
18. Using forEachRemaining()
The forEachRemaining() method processes every remaining element using a specified action. It is available through the Iterator interface and therefore can also be used with ListIterator.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ForEachRemainingExample {
public static void main(String[] args) {
List<String> tools = new ArrayList<>();
tools.add("Git");
tools.add("Maven");
tools.add("Gradle");
Iterator<String> iterator = tools.iterator();
iterator.forEachRemaining(System.out::println);
}
}
Output:
Git
Maven
Gradle
After processing the remaining elements, the iterator reaches the end of the collection.
19. Common Iterator Errors and Exceptions
| Error or Exception |
Cause |
How to Avoid It |
NoSuchElementException |
Calling next() or previous() when no element is available in that direction. |
Check hasNext() or hasPrevious() first. |
IllegalStateException |
Calling remove() or set() when the iterator is not in a valid state. |
Follow the required next()/previous() and modification rules. |
UnsupportedOperationException |
Using add(), remove(), or set() when the underlying collection does not support that operation. |
Use a collection that supports the required modification. |
ConcurrentModificationException |
Some fail-fast iterators detect structural changes made outside the iterator while iterating. |
Use the iterator's supported modification methods or a suitable concurrent collection. |
IndexOutOfBoundsException |
Passing an invalid index to listIterator(index). |
Use an index between 0 and list.size(), inclusive. |
20. Understanding ConcurrentModificationException
Many standard collection iterators are fail-fast. They may throw ConcurrentModificationException when the collection is structurally modified outside the iterator during iteration. This behavior is best-effort and should not be treated as a synchronization guarantee.
Incorrect Example
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
if (number == 20) {
numbers.remove(number);
}
}
This code modifies the list directly instead of using the iterator to remove the element. A fail-fast iterator may detect the structural change and throw ConcurrentModificationException.
Correct Example
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
if (number == 20) {
iterator.remove();
}
}
Using iterator.remove() keeps the removal operation coordinated with the iterator.
21. Practical Example: Managing a Student List
This example demonstrates using ListIterator to update student names, add a new entry, and traverse the list in reverse.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class StudentListManager {
public static void main(String[] args) {
List<String> students = new ArrayList<>();
students.add("Aarav");
students.add("Priya");
students.add("Rahul");
ListIterator<String> iterator = students.listIterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("Priya")) {
iterator.set("Priya Sharma");
}
if (name.equals("Rahul")) {
iterator.add("Neha");
}
}
System.out.println("Updated student list: " + students);
System.out.println("Reverse traversal:");
ListIterator<String> reverse = students.listIterator(students.size());
while (reverse.hasPrevious()) {
System.out.println(reverse.previous());
}
}
}
Output:
Updated student list: [Aarav, Priya Sharma, Rahul, Neha]
Reverse traversal:
Neha
Rahul
Priya Sharma
Aarav
Explanation: The program uses set() to replace Priya with Priya Sharma, then uses add() to insert Neha after Rahul. A second ListIterator starts at the end and traverses the list backward.
22. Best Practices for Iterator and ListIterator
- Use
hasNext() before calling next() in a standard forward loop.
- Use
hasPrevious() before calling previous().
- Use Iterator when forward traversal is sufficient.
- Use ListIterator when a list requires bidirectional traversal or insertion and replacement during iteration.
- Use
iterator.remove() or listIterator.remove() for supported removals during traversal.
- Do not call
remove() or set() before a valid call to next() or previous().
- Remember that not every collection supports every modification operation.
- Avoid modifying a collection directly while iterating over it with a fail-fast iterator.
- Use generics to ensure type safety, such as
Iterator<String>.
- Prefer the enhanced for loop for simple read-only traversal when explicit iterator operations are not needed.
23. Hands-On Exercises
Exercise 1: Display List Elements
Create an ArrayList of five programming languages and display all elements using Iterator.
Exercise 2: Remove Odd Numbers
Create a list of integers and use Iterator to remove all odd numbers.
Exercise 3: Reverse a List
Create a list of city names and use ListIterator to display them in reverse order.
Exercise 4: Replace an Element
Use ListIterator to replace a specific name in a list with a new name.
Exercise 5: Insert at a Cursor Position
Create a list of subjects and use ListIterator to insert a new subject after a selected element.
Exercise 6: Index Tracking
Use nextIndex() and previousIndex() to display the cursor's index before and after traversal operations.
24. Mini Project: To-Do List Manager
Objective: Create a simple To-Do List Manager using an ArrayList and ListIterator.
Project Requirements
- Store task names in an ArrayList.
- Display tasks using Iterator.
- Remove completed tasks during traversal.
- Replace an existing task description using ListIterator.
- Insert a new task at a specific cursor position.
- Display tasks in reverse order.
Sample Implementation
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class TodoListManager {
public static void main(String[] args) {
List<String> tasks = new ArrayList<>();
tasks.add("Complete Java notes");
tasks.add("Practice collections");
tasks.add("Submit assignment");
tasks.add("Review Iterator");
Iterator<String> iterator = tasks.iterator();
while (iterator.hasNext()) {
String task = iterator.next();
if (task.equals("Submit assignment")) {
iterator.remove();
}
}
ListIterator<String> listIterator = tasks.listIterator();
while (listIterator.hasNext()) {
String task = listIterator.next();
if (task.equals("Review Iterator")) {
listIterator.set("Revise Iterator and ListIterator");
listIterator.add("Practice coding exercises");
}
}
System.out.println("Final task list:");
for (String task : tasks) {
System.out.println(task);
}
System.out.println("Tasks in reverse order:");
ListIterator<String> reverse = tasks.listIterator(tasks.size());
while (reverse.hasPrevious()) {
System.out.println(reverse.previous());
}
}
}
This project combines forward traversal, safe iterator-based removal, element replacement, insertion, and backward traversal.
25. Interview Questions and Answers
Q1. What is an Iterator in Java?
Iterator is an interface used to traverse collection elements in the forward direction. It provides methods such as hasNext(), next(), and remove().
Q2. What is ListIterator?
ListIterator extends Iterator and is designed for lists. It supports forward and backward traversal, element insertion, element replacement, removal, and index information.
Q3. What is the main difference between Iterator and ListIterator?
Iterator supports forward traversal across many collection types. ListIterator is list-specific and supports backward traversal and additional modification operations.
Q4. Can Iterator traverse a list backward?
No. Iterator only supports forward traversal. Use ListIterator when backward traversal is required.
Q5. Can ListIterator modify a list?
Yes. It can insert, replace, or remove elements when the underlying list supports the corresponding operations and the iterator is in a valid state.
Q6. What does hasNext() do?
It returns true when another element is available in the forward direction, without advancing the iterator.
Q7. What happens when next() is called after the end?
It throws NoSuchElementException when no element remains.
Q8. What is the purpose of listIterator(index)?
It creates a ListIterator positioned at the specified valid index, so the next call to next() returns the element at that index.
Q9. Why can ConcurrentModificationException occur?
Some fail-fast iterators detect structural modifications made outside the iterator during traversal. Use supported iterator modification methods or an appropriate concurrent collection.
Q10. Can all iterators remove elements?
No. Removal is an optional operation. An iterator may throw UnsupportedOperationException if removal is not supported by the underlying collection.
26. Quick Revision Checklist
- Iterator belongs to the
java.util package.
iterator() obtains an Iterator from a collection.
hasNext() checks for another forward element.
next() retrieves the next element.
remove() removes the last returned element when supported.
- ListIterator extends Iterator and works with lists.
- ListIterator supports
previous() and hasPrevious().
add() inserts at the cursor position.
set() replaces the last returned element.
nextIndex() and previousIndex() provide index information.
- Unsupported modification operations can throw
UnsupportedOperationException.
- Invalid iterator state can cause
IllegalStateException.
- Use iterator-based removal rather than directly modifying a collection during traversal.
27. Conclusion
Iterator and ListIterator are essential tools for traversing collections in Java. Iterator provides simple forward traversal and controlled removal, making it useful for processing lists, sets, and other collections.
ListIterator provides additional capabilities for lists, including backward traversal, cursor indexes, insertion, and replacement. Understanding their methods, valid usage rules, and common exceptions helps you write safer and more maintainable Java programs.
Practice the examples and mini project to build confidence in collection traversal and modification.
Continue Learning: Explore the Core Java Training course, register for a course demo, or visit the JustAcademy website.