What is an Iterator in Java?
In Java, an iterator is a tool provided by the collection framework that helps you move through elements in a collection one by one. It allows you to access and modify elements efficiently without revealing how the collection is organized internally. The term “iterator” simply means going through each element. Iterator facilitates looping through collections such as ArrayList and HashSet.
To use an iterator, you just need to import it from the java.util package.
The basic syntax for using an Iterator in Java is as follows:
import java.util.ArrayList; import java.util.Iterator; public class IteratorSyntaxExample { public static void main(String[] args) { ArrayList<String> fruits = new ArrayList<>(); fruits.add("Apple"); fruits.add("Banana"); fruits.add("Orange"); fruits.add("Mango"); // Obtain an Iterator from the ArrayList Iterator<String> iterator = fruits.iterator(); // Using while loop to iterate through the elements while (iterator.hasNext()) { String fruit = iterator.next(); System.out.println(fruit); } } }
Output:
Explanation of this code:
- First, obtain an Iterator object from the collection you want to iterate through. You can do this by calling the iterator() method on the collection.
- Use a while loop or a for loop to traverse through the elements using the Iterator’s methods. The common methods used are hasNext() to check if there is another element and next() to retrieve the next element.
- In this example, we create an ArrayList of strings called fruits and add some elements to it. We then obtain an Iterator from the ArrayList using the iterator() We use a while loop with hasNext() and next() methods to traverse through the elements and print them one by one.
How Does Java Iterator Work Internally?
Internally, the Java Iterator works by maintaining a cursor or pointer that points to the current element in the collection being traversed. When you obtain an Iterator from a collection, the cursor is initially positioned before the first element.
When you call the hasNext() method, the Iterator checks if there is another element in the collection after the current cursor position. If an element is present, it returns true; otherwise, it returns false.
When you call the next() method, the Iterator moves the cursor to the next element and returns that element. The cursor then points to the next element in the collection.
The remove() method is used to remove the last element returned by the next() method. However, it can only be called after calling next(), and it removes the element at the cursor’s current position.
The Iterator keeps track of the traversal state, allowing you to move through the collection one element at a time, and it helps ensure that you don’t miss or repeat any elements during the iteration process.
Iterator Methods:
The Java Iterator interface offers the following methods:
- boolean hasNext(): This method checks if there are more elements in the collection and returns true if additional elements are available.
- Object next(): It returns the next object or element in the collection. If there are no more elements, it throws a NoSuchElementException error.
- void remove(): This method can only be used after calling the next() method, and it removes the current object where the iterator is positioned. Attempting to call remove() without first calling next() will result in an IllegalStateException error.
Note: The remove() method in the Java Iterator can throw two exceptions:
- UnsupportedOperationException: This exception is thrown if the remove operation is not supported by the iterator.
- IllegalStateException: This exception is thrown if the next() method has not been called yet, or if the remove() method has already been called after the last invocation of the next()
- forEachRemaining() is a Java Iterator method (introduced in Java 8) that executes an action on each remaining element in a collection using a lambda expression or method reference. It simplifies element iteration and action application without explicit loops. The method takes an action as input, performs it on remaining elements, and throws a NullPointerException if the action is null. Exceptions during execution are propagated to the caller.
Implementation of Iterator
In the given example, the implementation of hasNext(), next(), remove(), and forEachRemaining() methods of the Iterator interface is showcased for an array list. The code demonstrates how these methods are customized to efficiently navigate through the elements, remove elements, and iterate over the remaining elements in the list.
import java.util.ArrayList; import java.util.Iterator; public class IteratorExample { public static void main(String[] args) { // Creating an ArrayList ArrayList<Integer> list = new ArrayList<>(); list.add(10); list.add(30); list.add(20); System.out.println("ArrayList: " + list); // Creating an instance of Iterator Iterator<Integer> iterator = list.iterator(); // Using the next() method int element = iterator.next(); System.out.println("Accessed Element: " + element); // Using the remove() method iterator.remove(); System.out.println("Removed Element: " + element); System.out.print("Updated ArrayList: "); // Using the hasNext() method while (iterator.hasNext()) { // Using the forEachRemaining() method iterator.forEachRemaining((value) -> System.out.print(value + ", ")); } } }
Output:
Explanation of this code:
- We create an ArrayList called list and add three integer elements: 10, 30, and 20.
- We create an Iterator named iterator using the iterator() method of the ArrayList.
- We use the next() method to retrieve the first element from the ArrayList, which is 10. This element is stored in the variable element, and we print it as “Accessed Element: 10”.
- Next, we use the remove() method of the Iterator to remove the last element returned by next(), which is 10. So, the ArrayList now contains [30, 20]. We print “Removed Element: 10”.
- We then print “Updated ArrayList: “.
- Using the hasNext() method, we check if there are more elements in the ArrayList. Since there are two more elements (30 and 20), the loop proceeds.
- Inside the loop, we use the forEachRemaining() method with a lambda expression to print each remaining element in the ArrayList. The lambda expression (value) -> System.out.print(value + “, “) prints the element followed by a comma.
Advantages of using Iterator in Java:
- Abstraction: The Iterator provides a simple and user-friendly interface to traverse collections without needing to know their underlying implementation details.
- Efficient Iteration: Iterators are efficient for large datasets, as they allow sequential access without the need for direct indexing.
- Safe Removal: Iterators offer a safe mechanism to remove elements from a collection during iteration, avoiding concurrent modification exceptions.
- Code Reusability: Since the Iterator interface is implemented by all Java collection classes, the same code can be used to iterate over different types of collections, promoting code reusability.
Disadvantages of using Iterator in Java:
- Unidirectional: The Iterator is limited to moving forward through a collection, lacking the ability to move backward or access elements at arbitrary positions.
- Lack of Thread-safety: Iterators are not inherently thread-safe, requiring proper synchronization in multi-threaded environments to avoid concurrent modification issues.
- Limited Element Modification: While Iterators allow element removal, they lack direct support for modifying elements during iteration, necessitating the use of other interfaces like ListIterator or alternative looping mechanisms.