ListIterator and Bidirectional Traversal
Use ListIterator to traverse lists forwards and backwards and modify elements during iteration.
ListIterator and Bidirectional Traversal is a free Java Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
ListIterator
ListIterator<T> extends Iterator<T> with backward traversal, index-based positioning, and the ability to add and replace elements during iteration.
ListIterator API
Additional methods beyond Iterator: hasPrevious(), previous(), nextIndex(), previousIndex(), set(), add().
import java.util.*;
List<String> list = new ArrayList<>(List.of("A", "B", "C", "D"));
ListIterator<String> lit = list.listIterator();
// Forward traversal
while (lit.hasNext()) {
System.out.print(lit.nextIndex() + ":" + lit.next() + " ");
}
// 0:A 1:B 2:C 3:D
System.out.println();
// Backward traversal
while (lit.hasPrevious()) {
System.out.print(lit.previousIndex() + ":" + lit.previous() + " ");
}
// 3:D 2:C 1:B 0:AStarting at a Position
Create a ListIterator starting at a specific index with listIterator(index).
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30, 40, 50));
// Start at index 2 (30)
ListIterator<Integer> lit = nums.listIterator(2);
System.out.println(lit.next()); // 30
System.out.println(lit.next()); // 40
System.out.println(lit.previous()); // 40
System.out.println(lit.previous()); // 30
System.out.println(lit.previous()); // 20set() During Iteration
set() replaces the last element returned by next() or previous(). This is efficient — O(1) for LinkedList, O(1) for ArrayList.
List<String> words = new ArrayList<>(List.of("hello", "world", "java"));
ListIterator<String> lit = words.listIterator();
while (lit.hasNext()) {
String word = lit.next();
lit.set(word.toUpperCase()); // replace each with uppercase
}
System.out.println(words); // [HELLO, WORLD, JAVA]add() During Iteration
add(element) inserts before the next position. The added element is not returned by a subsequent next() call — it is already "behind" the cursor.
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));
ListIterator<Integer> lit = numbers.listIterator();
while (lit.hasNext()) {
int n = lit.next();
lit.add(n * 10); // insert n*10 after each element
}
System.out.println(numbers); // [1, 10, 2, 20, 3, 30]Reversing a List In Place
Using ListIterator to reverse a list in O(n) without allocating a new list.
static <T> void reverse(List<T> list) {
ListIterator<T> front = list.listIterator(0);
ListIterator<T> back = list.listIterator(list.size());
for (int i = 0, n = list.size() / 2; i < n; i++) {
T frontVal = front.next();
T backVal = back.previous();
front.set(backVal);
back.set(frontVal);
}
}
List<String> data = new ArrayList<>(List.of("a","b","c","d","e"));
reverse(data);
System.out.println(data); // [e, d, c, b, a]nextIndex and previousIndex
nextIndex() returns the index of the element that would be returned by next(). previousIndex() returns the index of the element that would be returned by previous().
List<String> list = List.of("X", "Y", "Z");
ListIterator<String> lit = list.listIterator();
System.out.println(lit.nextIndex()); // 0
System.out.println(lit.previousIndex()); // -1 (before start)
lit.next(); // consume X
System.out.println(lit.nextIndex()); // 1
System.out.println(lit.previousIndex()); // 0LinkedList ListIterator Performance
LinkedList's ListIterator achieves O(1) next/previous because traversal is pointer-following. get(i) on LinkedList is O(n) — use ListIterator to traverse efficiently.
import java.util.*;
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 5; i++) list.add(i * 10);
// Efficient: O(n) total for traversal via ListIterator
ListIterator<Integer> lit = list.listIterator();
while (lit.hasNext()) {
int val = lit.next();
if (val == 20) lit.set(99); // O(1) update
}
System.out.println(list); // [0, 10, 99, 30, 40]Palindrome Check with ListIterator
An elegant bidirectional traversal example: checking if a list is a palindrome.
static <T> boolean isPalindrome(List<T> list) {
ListIterator<T> front = list.listIterator(0);
ListIterator<T> back = list.listIterator(list.size());
for (int i = 0, n = list.size() / 2; i < n; i++) {
if (!front.next().equals(back.previous())) return false;
}
return true;
}
System.out.println(isPalindrome(List.of(1, 2, 3, 2, 1))); // true
System.out.println(isPalindrome(List.of(1, 2, 3, 4))); // falseIterator vs ListIterator Comparison
Key differences:
- Iterator: forward only, hasNext/next/remove
- ListIterator: bidirectional, hasPrevious/previous, nextIndex/previousIndex, set/add
- ListIterator only for Lists (not Set, Queue)
Undo/Redo with ListIterator
A cursor-based text editor using ListIterator for efficient undo/redo character navigation.
import java.util.*;
class TextEditor {
private final LinkedList<Character> chars = new LinkedList<>();
private ListIterator<Character> cursor;
TextEditor() { cursor = chars.listIterator(); }
void type(char c) { cursor.add(c); } // insert before cursor
void moveCursorLeft() { if (cursor.hasPrevious()) cursor.previous(); }
void moveCursorRight() { if (cursor.hasNext()) cursor.next(); }
void backspace() {
if (cursor.hasPrevious()) { cursor.previous(); cursor.remove(); }
}
String text() {
StringBuilder sb = new StringBuilder();
chars.forEach(sb::append);
return sb.toString();
}
}
TextEditor ed = new TextEditor();
ed.type('H'); ed.type('e'); ed.type('l'); ed.type('o');
ed.moveCursorLeft(); ed.moveCursorLeft();
ed.type('l');
System.out.println(ed.text()); // HelloWhen to Use ListIterator
Use ListIterator when you need:
- Backward traversal of a list
- Replacing elements during traversal with set()
- Inserting elements during traversal with add()
- Position tracking via nextIndex()/previousIndex()
Quick Check
What does ListIterator.set() do?
Recap: ListIterator and Bidirectional Traversal
Key takeaways:
- ListIterator extends Iterator with hasPrevious(), previous(), set(), add()
- Create a ListIterator at a specific position: listIterator(index)
- set() replaces the last element returned by next() or previous()
- add() inserts before the current cursor position
- nextIndex() and previousIndex() provide position awareness
- Use LinkedList ListIterator for O(1) traversal and modification
Frequently asked questions
Is the “ListIterator and Bidirectional Traversal” lesson free?
Yes — the full text of “ListIterator and Bidirectional Traversal” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “ListIterator and Bidirectional Traversal”?
Use ListIterator to traverse lists forwards and backwards and modify elements during iteration. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “ListIterator and Bidirectional Traversal” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Iterable and Iterator Contracts
- Implementing a Custom Iterator
- ListIterator and Bidirectional Traversal
- Fail-Fast vs Fail-Safe Iterators