July 05, 2024

#Collections: A Guide to Iterator in Java



What is an Iterator?

Iterator is an interface, which is found in java.util package. It provides a way to access elements of a collection sequentially without exposing its underlying implementation. 

The iterator allows the traversal of elements and supports removing elements during iteration. The Iterator interface has three main methods:
  • boolean hasNext(): Returns true if there are more elements in the collection.
  • E next(): Returns the next element in the collection.
  • void remove(): Removes the last element returned by next() from the collection (optional operation).

What is the difference between Iterator and Enumeration?

  • Enumeration is older and its there from JDK1.0, while iterator was introduced later.
  • The main difference between Iterator and Enumeration is that Iterator has the remove() method while Enumeration doesn't. Hence, using Iterator we can manipulate objects by adding and removing the objects from the collections. Enumeration behaves like a read only interface as it can only traverse the objects and fetch them.
  • Enumeration is twice as fast as compared to an Iterator and uses very less memory. 
  • Iterator is more secure and safe as compared to Enumeration because it does not allow other threads to modify the collection object while some thread is iterating over it and throws ConcurrentModificationException.
  • Enumeration methods hasMoreElement() and nextElement(). Iterator methods hasNext(), next() and remove().

Which design pattern is followed by the Iterator?

It follows an iterator design pattern. The iterator design pattern provides us to navigate through the collection of objects by using a common interface without letting us know about the underlying implementation.

Enumeration is also an example of an Iterator design pattern.

If an ArrayList has to be iterated to read data only, what are the possible ways and which is the fastest?

It can be done in two ways, using for loop or using iterator of ArrayList. The first option is faster than using an iterator. Because the value stored in ArrayList is indexed access. So while accessing the value is accessed directly as per the index.

If accessing through iterator is slow then why do we need it and when to use it.

For loop does not allow the updation in the array(add or remove operation) inside the loop whereas the Iterator does. Also, an Iterator can be used where there is no clue what type of collections will be used because all collections have an iterator.

What is the difference between Iterator and ListIterator?

  • An Iterator can be used to traverse the Set and List collections, while the ListIterator can be used to iterate only over List implementations (like ArrayList or LinkedList).
  • The Iterator can traverse a collection only in the forward direction, while the ListIterator can traverse a List in both directions  (next() and previous() methods).
  • The ListIterator implements the Iterator interface and contains extra functionality, such as adding an element, replacing an element, getting the index position for previous and next elements, etc through set(), add(), and remove() methods.

Explain the methods present in ListIterator?

ListIterator has these methods: add(), hasNext(), hasPrevious(), nextIndex(), next(), previousIndex(), previous(), remove(), set().
  • void add(E  e): The add() method of ListIterator interface is used to insert the given element into the specified list. The element is inserted automatically before the next element may return by next() method. This method may throw UnsupportedOperationalArgument (if the add() method is not supported by the given list iterator), ClassCastException (if the class of some of the elements avoids it from being added to the list) or IllegalArgumentException (if some of the element avoids it from being added into the list).
  • boolean hasNext(): The hasNext() method of ListIterator interface is used to return true if the given list iterator contains more number of elements during traversing the given list in the forward direction, else it will return false.
  • boolean hasPrevious(): It returns true if the list iterator has more elements when traversing the list in the backward direction.
  • int nextIndex(): It return the index of the element which is returned by the next() method. The method may also return the list size only if the list iterator is placed at the end of the list.
  • int previousIndex(): It returns the index of the given element which is returned by a call to previous. The method may return -1 if and only if the iterator is placed at the beginning of the list.
  • public E next(): It returns the next element in the given list. This method is used to iterate through the list. The next() can throw NoSuchElementException if there are no elements left in the iteration.
  • public E previous(): It return the previous element of the given list. The previous() method can throw NoSuchElementException, if the given iteration has no such previous elements.
  • void remove(): The remove() method of ListIterator interface is used to remove the last element from the list which is returned by the next() or previous() method. The above method can only be called if the add(E) has not been called. The remove() method of the ListIterator interface can throw UnsupportedOperationException (if the given remove operation is not supported by the list iterator) or IllegalStateException (if neither the next() nor the previous() method has been called).
  • void set(E  e): The set() method of the ListIterator interface is used to replace the last element which is returned by the next() or previous() along with the given element. The call can be added only if neither remove() nor add(E) methods have been called. It can throw UnsupportedOperationException (if the given set operation is not supported by the list iterator), ClassCastException (if the given class of the specified element is not supported by the list iterator), IllegalArgumentException (if some of the aspects of the given element avoid it from being added to the list) or IllegalStateException (if neither the next() nor the previous() method has been called).

What is the ConcurrentModificationException in Java?


ConcurrentModificationException is thrown when a collection is structurally modified (elements added or removed) while an iterator is in use. This happens when the iterator detects that the collection's modCount (modification count) has changed from its expected value, indicating a concurrent modification. It ensures fail-fast behaviour to prevent concurrent access issues and potential data corruption.

What is the difference between fail-fast and fail-safe Iterators?

Fail-fast Iterators throw ConcurrentModificationException when one Thread is iterating over the collection object and another thread structurally modifies the Collection either by adding, removing or modifying objects on the underlying collection. They are called fail-fast because they try to immediately throw Exceptions when they encounter failure.

Whereas fail-safe iterator traverses over a copy or view of the original collection.

Most of the Collection classes from Java 1.4 e.g. ArrayList, HashMap, HashSet has fail-fast iterators.

The other type of iterator was introduced in Java 1.5 when concurrent collection classes e.g. ConcurrentHashMap, CopyOnWriteArrayList and CopyOnWriteArraySet were introduced. This iterator uses a view of the original collection for doing iteration and that's why they don't throw ConcurrentModificationException even when the original collection was modified after iteration has begun.  This means you could iterate and work with stale value, but this is the cost you need to pay for a fail-safe iterator.

How do Fail-fast iterators know about the modification in the Collection?


Fail-fast iterators detect if a collection has been modified structurally (i.e., elements added or removed) after the iterator was created. If such a modification is detected, the iterator throws a ConcurrentModificationException when the next() or remove() methods are called.

This is achieved by maintaining an internal modCount (modification count) in the collection. The iterator checks this modCount against the expected modification count at the time of creation. If they differ, it indicates a modification, triggering the exception.

FYI, the Fail-Safe iterators often work on snapshots or copies of the collection's data. They do not directly check for modifications but ensure that any modifications during iteration do not affect the ongoing iteration process. Modifications may or may not be visible to these iterators, depending on the specific implementation.

What is the difference between the remove() method of Collection and the remove() method of Iterator?

The collection interface defines the remove(Object obj) method to remove objects from the Collection. List interface adds another method remove(int index), which is used to remove object at specific index. You can use any of these methods to remove an entry from the Collection, while not iterating.

But, you should not use Collection's or List's remove() method during iteration then your code will throw ConcurrentModificationException. Instead use the Iterator's remove() method, which removes the current element from Iterator's perspective.

How can you safely modify a collection while iterating over it?

Use ListIterator instead of Iterator for List implementations, as ListIterator supports safe modifications during iteration. Alternatively, use thread-safe collections such as CopyOnWriteArrayList or synchronize access to the collection manually using synchronized blocks or methods.

Ensure modifications are done using the iterator's own remove() method (or ListIterator's remove(), set(), and add() methods) to avoid ConcurrentModificationException.

Can you remove an element from a collection using an Iterator while iterating?

Yes, we can remove elements from a collection safely using an iterator. The correct approach is to use the remove() method of the iterator itself, rather than directly using the collection's remove() method. This avoids ConcurrentModificationException and ensures that the iterator remains in a consistent state.

-K Himaanshu Shuklaa..

No comments:

Post a Comment