The Java collections framework gives the programmer access to prepackaged data structures as well as to algorithms for manipulating them.
A collection is an object that can hold references to other objects. The collection interfaces declare the operations that can be performed on each type of collection.
The classes and interfaces of the collections framework are in package java.util.
We often have to traverse through these collection objects as per our requirements. When one thinks of traversing, looping concept is the first thing that comes to our mind. Yes, loops are very beneficial for traversing through any data. But the easiest way is to employ an iterator. Iterators serve as indispensable tools for navigating collections, offering a seamless way to access and manipulate elements. Let's discuss more about iterators in this article. It is a universal iterator as we can apply it to any Collection object. By using Iterator, we can perform both read and remove operations.
Now, one might think why do we need Iterator when we have for-each loop?
In for-each loop, we can’t modify collection, it will throw a ConcurrentModificationException(any modification is done in the collection during the iteration) on the other hand with iterator we can modify collection. In iterator this can be handled by using iterator's remove() method instead of directly modifying the collection.
Here are some of the reasons why iterators might be preferred in certain scenarios:
Enhance readability : Iterators can make the code more readable, especially when dealing with complex data structures. The iterator pattern hides the internal implementation, making the code cleaner and easy to understand.
Uniform Interface: Iterators provide a uniform way to traverse various types of collections (e.g., lists, sets, maps). This can lead to more consistent and maintainable code.
Removal Support: Iterators often provide a remove() method that allows elements to be safely removed during iteration. This is especially useful when you need to modify the collection while traversing it. (For each loop has this limitation).
Specific Features for Collections: Some iterators provide specific or enhanced features which can be beneficial like ListIterator in ArrayList allows bidirectional traversal and modification of elements.
Concurrent Modification Safety: If the underlying collection is modified while iterating, the iterator detects it and throws a ConcurrentModificationException, preventing unpredictable behavior.
An iterator has these methods that are used to traverse through the collection:
hasNext() – This method checks if there is another element in the collection that can be iterated over.
next() – This method returns the next element in the collection.
remove() – This method removes the current element from the collection.
forEachRemaining(): Performs the given action for each remaining element in a collection, in sequential order.
The Iterator interface is a part of the Java Collection Framework, and it is implemented by the classes that represent the different types of collections.
Let's understand this with an example -
In the above code snippet, we have created an arraylist to store skills of an SDET.
Then, we have created "itr" object which acts as an iterator of the arraylist(list1). Here "itr" is an object of interface Iterator. The next step is to set up a loop that makes a call to hasNext( ). Have the loop iterate as long as
hasNext( ) returns true. The last step is within the loop, obtain each element by calling next( ). The output we obtain here is
Using an iterator to traverse through a collection is a convenient and efficient way of iterating through the collection because it allows the collection to be iterated over without knowing the internal structure of the collection. It also allows for the removal of elements from the collection while iterating over it.
How Does Java Iterator Work Internally?
Let's have a look at the below example in which we have created a linkedList object and we have added some elements in it.
List<String> elements = new LinkedList<>();
elements.add("G-1");
elements.add("G-2");
elements.add("G-3");
.
.
.
elements.add("G-n");
Now lets create an Iterator object for the linkedList object as below:
Iterator<String> elementsIterator = elements.iterator();
at this point, the cursor of java Iterator is at the beginning of the linkedList object.
Now, we run the following code snippet,
elementsIterator.hasNext();
elementsIterator.next();
This way iterator traverses through each element and displays the output. After reading the final element, if we run the below code snippet, it returns a “false” value.
elementsIterator.hasNext();
As we can see from the above diagrams, iterators moves only in one direction, which is in forward direction. That's the reason Iterator is also called as Uni-Directional Cursor.
Iterators can be better choice when dealing with Excel file read/write operations for several reasons. Some of them are :
Iterators provide a sequential way to access elements in a collection, which aligns well with the row-by-row or cell-by-cell structure of Excel files.
Using iterators abstracts away the complexity of accessing these elements, providing a cleaner and more readable code.
Iterators allow you to process data incrementally, handling one row or cell at a time, which is memory-efficient.
Iterators contribute to a clean and modular code structure.
In the above example, we have two iterators - rowIterator which iterates through the rows and cellIterator that iterates through the cells. Here we want to display each cell content on the console which is easily achieved by using two iterators instead of writing nested for loops. This makes the code easy to understand and hence maintainable.
Regardless of all these advantages of using iterators, they are not always perfect candidate in all situations/scenarios. Some of the limitations are mentioned below :
Traditional loops might be more familiar to some developers, and for simple iteration over arrays or collections, they can be concise and straightforward.
Traditional loops are often preferred when dealing with arrays or situations where direct index-based access to elements is necessary.
In certain scenarios, traditional loops might be slightly more performant, especially when iterating over arrays.
Comments