Signed in as @priyankanandula
Hello, Developers hope you guys are doing great 😃.Today I came up with an interesting and important concept in Java Collections
, as well as in interviews
. I hope you enjoy it.
Do you know what was the issue with using the for-loop
to iterate the Collection objects ❓
Let me explain this to you in such case 👇.
Let's take a look at the following code
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorDemo {
private static void arrayListDemo() {
List<Integer> list=new ArrayList<>();
list.add(5);
list.add(6);
list.add(7);
list.add(9);
for(int element:list) {
System.out.println("element : "+element);
if(element==6) {
list.remove(Integer.valueOf(7));
}
}
}
public static void main(String[] args) {
arrayListDemo();
}
}
OUTPUT :
element : 5
element : 6
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at IteratorDemo.arrayListDemo(IteratorDemo.java:14)
at IteratorDemo.main(IteratorDemo.java:27)
It was printed up to element 6, after which the element in the following index is 7, and we have put a condition to remove that element from the list
if it is 7 and here it was thrown
java.util.ConcurrentModificationException
NOTE : However, we can do
replacement operations
such as set method, and this exception will never be thrown.
Root Cause :
Internally, for-each
statement, it invokes the iterator function for the given object and iterates over the elements using the instance obtained by the iterator.
The iterator, which is internally written, generates the concurrent modification exception.
The iterator does not allow us to make any concurrent structural changes (removing/adding) to the underlying ArrayList.
Such Iterators which gives a concurrent modification exception are called fail-fast Iterator.
Solution :
The solution here is to use Iterator interface
and to access an instance of iterator we need to invoke the iterator method which is declared in the Iterable interface
.
Collection interface already extends the Iterable interface
and collection implementations like ArrayList, HashSet.. implements the Iterator method
.
public interface Collection
extends Iterable{..}
Collection interface is saying that its elements can be iterated by extending the Iterable
.
The `java.lang.Iterable` interface provides the following methods:
- iterator() : We can iterate the elements of Java Iterable by obtaining the Iterator from it using the iterator() method.
- forEach(Consumer<? super T> action) : Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.
- spliterator() : The Spliterator interface, can be used for traversing and partitioning sequences. It's a base utility for Streams, especially parallel ones.
The `java.util.Iterator` interface provides the following methods:
- boolean hasNext() - Returns true if the iteration has more elements.
- E next() - Returns the next element in the iteration.
- void remove() - Removes from the underlying collection the last element returned by the iterator (optional operation).
- forEachRemaining(Consumer<? super E>action) - Performs the given action on each of the element until and unless all the elements have been processed or unless an exception is thrown by the action.
Now, using the Iterator interface
, we'll rewrite the code to remove the element.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorDemo {
private static List<Integer> arrayListDemo() {
List<Integer> list=new ArrayList<>();
list.add(5);
list.add(6);
list.add(7);
list.add(9);
return list;
}
private static void iteratorDemo(List<Integer> list1) {
System.out.println("\nInside iteratorDemo ... ");
Iterator<Integer> iterator = list1.iterator();
while (iterator.hasNext()) {
int element = iterator.next();
System.out.println("element: " + element);
if (element == 9) {
iterator.remove();
}
}
System.out.println("List After removing the element " + list1);
}
public static void main(String[] args) {
List<Integer> list1 = arrayListDemo();
iteratorDemo(list1);
}
}
OUTPUT :
Inside iteratorDemo ...
element: 5
element: 6
element: 7
element: 9
List After removing the element [5, 6, 7]
Yo 🤘 ! It doesn't throw any exceptions anymore.
NOTE : The invocation of remove method must be preceded by the invocation of next() method otherwise it will throw an exception.Because the remove method will removes the element that was returned by the next() method.
For Example : Sample Code
while (iterator.hasNext()) {
int element = iterator.next();
System.out.println("element: " + element);
if (element == 9) {
iterator.remove();
iterator.remove();
}
}
OUTPUT
Inside iteratorDemo ...
element: 5
element: 6
element: 7
element: 9
Exception in thread "main" java.lang.IllegalStateException
at java.util.ArrayList$Itr.remove(Unknown Source)
at IteratorDemo.iteratorDemo(IteratorDemo.java:30)
at IteratorDemo.main(IteratorDemo.java:40)
It will throw an exception at the second remove method because it has to be preceded by next() method only.
Generally the use case of this scenario like removing during the iteration could be that you may have retrieved a list of elements form the database and now you want to remove some of them which meets certain criteria.
This is priyanka nandula signing off...
Top comments (0)