It's tricky to remove objects from ArrayList in Java while you are not iterating over it, especially if you are new to Java programming. Although, you can use any of the overloaded remove(object obc) and remove (int index) method to remove objects directly or at any index. But, things get tricky, when you are iterating over ArrayList. If you use the remove() method from ArrayList then it will throw ConcurrentModificationException, even if you are running your code from single thread. The reason is that, Iterator checks for any modification during iteration using modCount and if it sees a modification e.g. add or remove which happens outside Iterator, it throws ConcurrentModificationException.
Hence, the right way to remove objects from ArrayList is to use the Iterator's remove method, instead of remove() methods from ArrayList. It will help you to avoid ConcurrentModficiationException.
The Iterator is an implementation of Iterator design pattern, which provides a consistent way to traverse a Collection class without worrying about implementation.
For example, you can iterate over an ArrayList in the same way as LinkedList or Vector if you use Iterator. It provides hasNext() method to check if there is any more elements remaining on List and next() method to get the next object from the List.
The java.util.Iterator was added in JDK 1.4, before this Java programmer used to use Enumeration class for traversing over ArrayList. It also provides methods to get the next elements and check if there is any element or not, but it doesn't provide any method to remove elements from ArrayList.
That's actually the most important difference between Iterator and Enumeration in Java, one of the frequently asked java Interview questions.
Let's see an example of removing objects from ArrayList while iterative over List in Java. Suppose, we have a list of job offers and total CTC, we want to go through the list and remove all job offers which are offering lower or same CTC as your current job.
Here is our Java class which represents a job offer.
class JobOffer implements Comparable < JobOffer > {
String position;
int CTC;
public JobOffer(String position, int cTC) {
super();
this.position = position;
CTC = cTC;
}
public String getPosition() {
return position;
}
public int getCTC() {
return CTC;
}
public void setPosition(String position) {
this.position = position;
}
public void setCTC(int cTC) {
CTC = cTC;
}
@Override
public String toString() {
return "JobOffer [position=" + position + ", CTC=" + CTC + "]";
}
@Override
public int compareTo(JobOffer o) {
int i = this.position.compareTo(o.position);
if (i != 0) return i;
return Integer.compare(this.CTC, o.CTC);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + CTC;
result = prime * result +
((position == null) ? 0 : position.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof JobOffer))
return false;
JobOffer other = (JobOffer) obj;
if (CTC != other.CTC)
return false;
if (position == null) {
if (other.position != null)
return false;
} else if (!position.equals(other.position))
return false;
return true;
}
}
If you are storing an object on Collection class, make sure you override equals and hashCode() methods because Collection classes e.g. ArrayList uses these methods to search or remove elements from the List.
You should also override Comparable method if you want to compare one instance of this class with other instance, or you want to store them into Sorted collections e.g. SortedSet like TreeSet and TreeMap.
One more thing to note is that, if you override both equals() and compareTo() method for a class, make sure they are consistent with each other i.e. if two objects are equal by equals() method, they must be same by compareTo() as well i.e. they must return zero.
Btw, I have made this class non-public because both my test code i.e. main method and this class are in the same Java source file and which only contains one public class or interface, whose name also must be same as of Java source file.
If you want, you can move this class to its own file, which is also the recommended way, until its not an inner or nested class.
Anyway, here is our list of job offers, which we'll evaluate by traversing over ArrayList and going through each JobOffer and removing any offer where CTC is lower than or equal to current CTC, obviously you need increment right?
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
* Java Program to remove objects from ArrayList during
* iteration.
*/
public class Demo {
public static void main(String[] args) throws Exception {
//a list of job offers for Java developers
List < JobOffer > listOfJobOffers = new ArrayList < > ();
listOfJobOffers.add(new JobOffer("Java Develoepr", 90000));
listOfJobOffers.add(new JobOffer("Senior Java Develoepr", 110000));
listOfJobOffers.add(new JobOffer("Java Programmer", 80000));
listOfJobOffers.add(new JobOffer("Java Software Engineer", 93000));
listOfJobOffers.add(new JobOffer("Programmer", 97000));
listOfJobOffers.add(new JobOffer("Senior Java Programmer", 120000));
System.out.println("initial list of job offers: " + listOfJobOffers);
//let's remove objects form ArrayList while iterating
// remove all job offers which is equal to or lower than current CTC
int currentCTC = 90000;
Iterator < JobOffer > iterator = listOfJobOffers.iterator();
while (iterator.hasNext()) {
JobOffer offer = iterator.next();
if (offer.CTC <= currentCTC) {
iterator.remove();
}
}
System.out.println("list of job offers after removing objects: "
+ listOfJobOffers);
}
}
And here is the output of the program when you run it:
initial list of job offers: [JobOffer [position=Java Develoepr, CTC=90000], JobOffer [position=Senior Java Develoepr, CTC=110000], JobOffer [position=Java Programmer, CTC=80000], JobOffer [position=Java Software Engineer, CTC=93000], JobOffer [position=Programmer, CTC=97000], JobOffer [position=Senior Java Programmer, CTC=120000]]
list of job offers after removing objects: [JobOffer [position=Senior Java Develoepr, CTC=110000], JobOffer [position=Java Software Engineer, CTC=93000], JobOffer [position=Programmer, CTC=97000], JobOffer [position=Senior Java Programmer, CTC=120000]]
You can see that initially, there were 6 object were present in the ArrayList but after iteration only 4 of them remained because we have removed two job offers where CTC is not as per expectation. The key thing to note here is that we have use the Iterator's remove method and not the ArrayList's remove method.
If you change the code inside if block as below, you will see ConcurrentModificationException:
if(offer.CTC <= currentCTC){
listOfJobOffers.remove(offer);
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at Demo.main(Demo.java:31)
This happens because Iterator checks for modification after each iteration and it failed if modCount doesn't match with the expected value. If you use Iterator's remove() method then modCount is also updated.
Btw, there are multiple ways to iterate over ArrayList in Java e.g. you can use both enhanced for loop and classical for loop to traverse over a List, how do you remove element in such cases? Well, there is no way to remove elements from ArrayList if you are traversing using enhanced for loop, while loop or for loop without using Iterator.
The only way to delete object while going through list is by using Iterator's remove method.
For example, following code will throw "Exception in thread "main" java.util.ConcurrentModificationException" because we are using remove method from java.uti.ArrayList class:
int currentCTC = 90000;
for (JobOffer offer: listOfJobOffers) {
if (offer.CTC <= currentCTC) {
listOfJobOffers.remove(offer);
}
}
You can try and run this code by yourself to check if it throw Exception at runtime or not.
That's all about how to remove objects from ArrayList while iterating over it. Bottom line is never use the remove() methods from javal.util.ArrayList, they will throw ConcurrentModificationException. Instead, use Iterator's remove() method for removing objects while iterating.
You should also use Iterator, because that's the only option to modify collection during iteration, all other options e.g. enhanced for loop are read only way to traverse the List.
Other Java ArrayList and Collection Tutorials for Programmers
- How to convert ArrayList to Set in Java? (read more)
- How to sort an ArrayList in reverse order in Java? (solution)
- How to remove duplicate elements from ArrayList in Java? (solution)
- How to clone an ArrayList in Java? (solution)
- How to make an ArrayList unmodifiable in Java? (solution)
- Performance comparison of contains() vs binarySearch() in Java (read more)
- How to initialize an ArrayList with values in Java? (example)
- The ArrayList Guide in Java(tutorial)
- The difference between an ArrayList and a Vector in Java? (answer)
- ArrayList clear() vs removeAll in Java (answer)
- 21 ArrayList interview questions with answers (ArrayList questions)
- How do you convert a Map to a List in Java? (solution)
- How to sort ArrayList by multiple fields in Java? (sort a list)
- How to remove an entry from Map while iterating in Java?
Thanks for reading this article so far. If you like this tutorial and my example of ArrayList.clear() and ArrayList.removeAll() method to empty an ArrayList in Java then please share with your friends and colleagues. If you have any questions, please drop a note.
P. S. - If you are keen to level up your Java collections skills and need resources then I highly recommend you to check out these best Java collections and Stream Courses to start with. It contains some high-quality online courses to master both Collections and Stream API in Java.
Thanks a lot for reading this article so far. If you like this tutorial then please share with your friends and colleagues.
What is your favorite way to remove objects from ArrayList in Java? remove(int), remove(object) or anything else? Let me know in comments.
1 comment :
It's simple when you are using Iterator, always use Iterator's remove() method to remove objects from Collection. This is the correct way and that should be your favorite also if you don't want to introduce bug in your code, otherwise, happy coding !!
Post a Comment