Java Collection Traversal delete specified element exception analysis summary

Source: Internet
Author: User
Tags throw exception concurrentmodificationexception

In the process of using the collection, we often have to iterate over the collection elements, delete the requirements of the specified elements, and for this demand we often use will make small mistakes, resulting in the program throws an exception or with the expected result is wrong, I have encountered this hole very early, then did not pay attention to the summary, the results of the previous time encountered this problem, , summarizes how to delete the specified element in the collection while traversing the collection;

1. Error scenario Recovery

public class Listremovetest {public static void main (string[] args) {list<user> users = new arraylist<user> (); Users.add (New User ("Liu1")), Users.add (New User ("Liu2"), Users.add (New User ("Liu3"), Users.add ("New user"); Liu4 ",");iterator<user> Iterator = Users.iterator (); while (Iterator.hasnext ()) {User user = Iterator.next (); if (User.getname (). Equals ("Liu2")) {users.remove (user);} SYSTEM.OUT.PRINTLN (user);}}}

or the following code

public class Listremovetest {public static void main (string[] args) {list<user> users = new arraylist<user> (); Users.add (New User ("Liu1")), Users.add (New User ("Liu2"), Users.add (New User ("Liu3"), Users.add ("New user"); Liu4 "," ());        for (user user:users) {if (User.getname (). Equals ("Liu2")) {users.remove (user);} SYSTEM.OUT.PRINTLN (user);}}}

Both of these usages will run the following exception:

2. Cause analysis

The above two kinds of errors, I think many people have met, this is our easy to make mistakes, but why the above exception, how can we correctly traverse the collection at the same time, delete the specified element!

2.1 Cause Resolution

First, for a foreach loop traversal, essentially an iterator pattern, the for statement above is equivalent to the following code:

for (iterator<user> Iterator = Users.iterator (); Iterator.hasnext ();) {User user = Iterator.next (), if (User.getname (). Equals ("Liu2")) {users.remove (user);} SYSTEM.OUT.PRINTLN (user);}

Therefore, the nature of the above error, it is necessary to look at the source of the iterator iterator

In ArrayList, its modify operation (Add/remove) modcount This field +1,modcount can be regarded as a version number, each time the elements in the collection are modified, will be +1 (even if overflow).

  public boolean remove (Object o) {        if (o = = null) {for            (int index = 0; index < size; index++)                if (ELEMENTDA Ta[index] = = null) {                    fastremove (index);                    return true;                }        } else {for            (int index = 0; index < size; index++)                if (O.equals (Elementdata[index])) {                    fastremove (index);                    return true;                }        }        return false;    } private void Fastremove (int index) {        modcount++;        int nummoved = size-index-1;        if (nummoved > 0)            system.arraycopy (Elementdata, index+1, Elementdata, index,                             nummoved);        Elementdata[--size] = null; Clear to let GC do it work    }

Then look at the Iteraor method in Absrtactlist

Public iterator<e> Iterator () {    return new Itr ();}

It returns an inner class that implements the iterator interface with the following code:

Private class Itr implements iterator<e> {int cursor = 0;    int lastret =-1;    int expectedmodcount = Modcount;    public Boolean Hasnext () {return cursor! = size ();        } public E Next () {checkforcomodification ();            try {E next = get (cursor);            Lastret = cursor++;        return next;            } catch (Indexoutofboundsexception e) {checkforcomodification ();        throw new Nosuchelementexception ();        }} public void Remove () {if (Lastret = =-1) throw new IllegalStateException ();        Checkforcomodification ();            try {AbstractList.this.remove (Lastret);            if (Lastret < cursor) cursor--;            Lastret =-1; Modifying the value of a expectedmodcount expectedmodcount =  modcount; } catch (Indexoutofboundsexception e) {throw new concurrentmodificationexception (); }    }final void Checkforcomodification () {if (Modcount! = expectedmodcount) throw new concurrentmodific    Ationexception (); }}

In the inner class ITR, there is a field expectedmodcount that is initialized equal to Modcount, that is, when we call List.iterator () to return an iterator, the field is initialized to be equal to Modcount. The Next/remove method in class ITR has a call to the Checkforcomodification () method, in which modcount = = Expectedmodcount is detected, If not equal, the concurrentmodificationexception is thrown.

As stated earlier, in the set modification operation (Add/remove), the Modcount was +1.

During the iteration, execute List.remove (val), make Modcount+1, Next loop, execute It.next (), checkforcomodification method found Modcount! = Expectedmodcount, an exception is thrown.

2.2 Expected result is not correct, but not throw exception

Note: There is also a more pit scene, when the second-to-last element of the collection is deleted, the program will not throw any exception, but the result is not consistent with the expected, if not carefully observed during the application, it is difficult to find the error!

The error example is as follows:

public static void Main (string[] args) {list<user> users = new arraylist<user> (); Users.add (New User ("Liu1", 24));
Users.add (New User ("Liu2")), Users.add (New User ("Liu3", 24));
Users.add (New User ("Liu4"));iterator<user> Iterator = Users.iterator ();
while (Iterator.hasnext ()) {
User user = Iterator.next ();
if (User.getname (). Equals ("liu3")) {
Users.remove (user);
}
SYSTEM.OUT.PRINTLN (user);
}}

The results of the operation are as follows:

The traversal process removes the second-to-last element, and the final element is never traversed , the main reason is that the iterator source in the Hasnext method, determine whether the current element subscript and the collection size is equal

public Boolean hasnext () {
return cursor! = size;
}

When the second-to-last element is deleted, the current element subscript and the collection are the same size, jumping out of the loop, it will traverse the final collection element;

3. Correct usage

To remove a specified element during a collection traversal, it is important to use the Remove method of the iterator itself;
Then take a look at the Remove () method of the inner class ITR, after deleting the element, there is a sentence Expectedmodcount = Modcount, which synchronously modifies the value of Expectedmodcount. So, if you need to delete an element while using an iterator iteration, you can use the Remove method provided by the iterator. The same is true for other collections (Map/set) using iterator iterations.

So Iterator is not allowed to be changed by iterative objects while working.
But you can delete the object using Iterator's own method remove ( ), and the Iterator.remove () method maintains the consistent index while deleting the current iteration object

The specific correct usage code is as follows:

public class Listremovetest {

public static void Main (string[] args) {
list<user> users = new arraylist<user> ();
Users.add (New User ("Liu1", 24));
Users.add (New User ("Liu2", 24));
Users.add (New User ("Liu3", 24));
Users.add (New User ("Liu4", 24));

iterator<user> Iterator = Users.iterator ();
while (Iterator.hasnext ()) {
User user = Iterator.next ();
if (User.getname (). Equals ("Liu2")) {
Iterator.remove ();
}
SYSTEM.OUT.PRINTLN (user);
}
System.out.println (users);
}
}

The results of the operation are as follows:

Consistent with expected results;

Java Collection Traversal delete specified element exception analysis summary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.