Table of Contents#
- Understanding the Need for Iterator in Range Deletion
- Basics of Java Iterator
- Deleting a Range of Values: Step-by-Step
- Example Implementations
- Common Pitfalls and Best Practices
- Alternative Approaches
- Real-World Use Cases
- Conclusion
- References
1. Understanding the Need for Iterator in Range Deletion#
Problem with Enhanced for Loop#
The enhanced for loop (e.g., for (T element : list)) uses an implicit iterator. If you modify the list (e.g., list.remove(element)) during iteration, the iterator’s internal state (tracking modifications) gets out of sync, triggering a ConcurrentModificationException.
Problem with Index-Based for Loop#
An index-based for loop (e.g., for (int i=0; i<list.size(); i++)) works but is error-prone:
- Deleting an element shifts subsequent indices, leading to skipped elements or
IndexOutOfBoundsException. - Complex logic for range-based deletion (e.g., deleting elements between indices
xandy) becomes hard to manage.
2. Basics of Java Iterator#
The java.util.Iterator interface provides methods to traverse and modify a collection safely during iteration:
| Method | Description |
|---|---|
hasNext() | Checks if there is a next element (returns true/false). |
next() | Returns the next element (throws NoSuchElementException if none exists). |
remove() | Deletes the last element returned by next() (throws IllegalStateException if misused). |
Simple Example: Removing a Single Element#
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class IteratorBasics {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
Iterator<String> it = fruits.iterator();
while (it.hasNext()) {
String fruit = it.next();
if (fruit.equals("Banana")) {
it.remove(); // Safely remove "Banana"
}
}
System.out.println(fruits); // Output: [Apple, Cherry]
}
}3. Deleting a Range of Values: Step-by-Step#
To delete a range of values (e.g., elements between two values, indices, or a condition):
Step 1: Define the Range#
- Value-based range: Delete elements between
minandmax(e.g., all integers from5to10). - Index-based range: Delete elements at indices
starttoend(e.g., indices1to3). - Condition-based range: Delete elements matching a predicate (e.g., all strings longer than 5 characters).
Step 2: Iterate with Iterator#
- Use
hasNext()to check for remaining elements. - Use
next()to fetch the current element. - Check if the element falls within the range.
- If yes, call
remove()to delete it.
4. Example Implementations#
Example 1: Value-Based Range Deletion (Integers 5–10)#
Delete all integers between 5 and 10 (inclusive) from a list:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class RangeDeletionValue {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 6, 3, 8, 10, 4, 9));
System.out.println("Before: " + numbers);
Iterator<Integer> it = numbers.iterator();
while (it.hasNext()) {
Integer num = it.next();
// Check if num is in [5, 10]
if (num >= 5 && num <= 10) {
it.remove(); // Delete the element
}
}
System.out.println("After: " + numbers); // Output: [1, 3, 4]
}
}Example 2: Index-Based Range Deletion (Indices 1–3)#
Delete elements at indices 1, 2, and 3 (0-based) from a list:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class RangeDeletionIndex {
public static void main(String[] args) {
List<String> items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
System.out.println("Before: " + items);
Iterator<String> it = items.iterator();
int currentIndex = 0; // Track the index manually
while (it.hasNext()) {
String item = it.next();
// Delete elements at indices 1, 2, 3
if (currentIndex >= 1 && currentIndex <= 3) {
it.remove();
}
currentIndex++; // Increment after processing the element
}
System.out.println("After: " + items); // Output: [A, E]
}
}Example 3: Condition-Based Range Deletion (Strings with Length > 5)#
Delete all strings longer than 5 characters:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class RangeDeletionCondition {
public static void main(String[] args) {
List<String> words = new ArrayList<>(Arrays.asList("Hello", "Programming", "World", "Java"));
System.out.println("Before: " + words);
Iterator<String> it = words.iterator();
while (it.hasNext()) {
String word = it.next();
// Delete words with length > 5
if (word.length() > 5) {
it.remove();
}
}
System.out.println("After: " + words); // Output: [Hello, World, Java]
}
}5. Common Pitfalls and Best Practices#
Common Pitfalls#
-
Calling
remove()withoutnext():
ThrowsIllegalStateException(e.g.,it.remove()beforeit.next()).// WRONG: remove() called without next() it.remove(); // Throws IllegalStateException -
Calling
remove()multiple times afternext():
Also throwsIllegalStateException(e.g.,it.remove(); it.remove();after onenext()). -
Modifying the list outside the iterator:
CausesConcurrentModificationException(e.g.,list.add("New")while iterating withIterator). -
Forgetting
hasNext()beforenext():
ThrowsNoSuchElementException(e.g.,it.next()when no elements remain).
Best Practices#
-
Always use
Iterator’sremove():
Never modify the list directly (e.g.,list.remove()) during iteration. -
Use a temporary variable for
next():
Store the element fromnext()in a variable to avoid re-fetching (e.g.,String elem = it.next();). -
Track indices (for index-based ranges):
Use a separate variable (e.g.,int index = 0;) to track the current index, asIteratordoes not expose indices. -
Use
ListIteratorfor bidirectional control:
For more control (e.g., reverse iteration, index access), useListIterator(supportsprevious(),nextIndex(), etc.). -
Synchronize for concurrent access:
If the list is shared across threads, synchronize access or use a concurrent collection (e.g.,CopyOnWriteArrayList).
6. Alternative Approaches#
Using ListIterator (Bidirectional Iteration)#
ListIterator extends Iterator and supports:
- Bidirectional movement (
previous(),next()). - Index tracking (
nextIndex(),previousIndex()). - In-place modifications (
add(),set(),remove()).
Example: Delete elements at indices 1–3 with ListIterator#
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorExample {
public static void main(String[] args) {
List<String> items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
System.out.println("Before: " + items);
ListIterator<String> lit = items.listIterator();
int startIndex = 1;
int endIndex = 3;
while (lit.hasNext()) {
int currentIndex = lit.nextIndex();
String item = lit.next();
if (currentIndex >= startIndex && currentIndex <= endIndex) {
lit.remove(); // Delete the element
}
}
System.out.println("After: " + items); // Output: [A, E]
}
}Using Java 8+ Streams (New List, Not In-Place)#
For creating a new list (not modifying the original), use streams with filter():
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 6, 3, 8, 10, 4, 9));
// Create a new list with elements NOT in [5, 10]
List<Integer> filtered = numbers.stream()
.filter(num -> num < 5 || num > 10)
.collect(Collectors.toList());
System.out.println("Filtered: " + filtered); // Output: [1, 3, 4]
}
}Pros: Concise, functional style.
Cons: Creates a new list (original remains unchanged).
7. Real-World Use Cases#
- Log File Processing: Remove log entries between two timestamps (value-based range).
- Batch Data Deletion: Delete old records (e.g., from a list of database entries) based on a date range.
- Game Development: Remove expired game objects (e.g., power-ups) from a list of active entities.
- Text Processing: Delete lines between two markers (e.g.,
<!-- START -->and<!-- END -->) from a list of strings.
8. Conclusion#
Using Iterator (or ListIterator) is the safest way to delete a range of values from a List in Java. It avoids ConcurrentModificationException and simplifies range-based deletion. Remember to:
- Use
hasNext()andnext()correctly. - Only call
remove()once pernext(). - Track indices (or use
ListIterator) for complex range logic.
For read-only filtering (creating a new list), Java 8+ streams offer a concise alternative.
9. References#
- Java Iterator Documentation
- Java ListIterator Documentation
- Baeldung: Java Iterator Guide
- Stack Overflow: Iterator Best Practices
This blog provides a comprehensive guide to safely deleting a range of values from a List using Iterator, with examples, best practices, and real-world applications.