Java Traversal HashMap and modify (remove) (reprint)

Source: Internet
Author: User
Tags delete key prev concurrentmodificationexception

There are many ways to traverse HashMap, for example, by acquiring map keyset, EntrySet, iterator, and so on, however, if you do not read the map in the traversal process, you need to pay attention to the use of the traversal mode and operation method.

public class Mapiteratortest {     private static Map<integer, string> Map = new Hashmap<integer, string> (); C1/>public static void Main (string[] args) {        //init        for (int i = 0; i <; i++) {            map.put (i, "value" + i); 
   }         for (Map.entry<integer, string> entry:map.entrySet ()) {             Integer key = Entry.getkey ();             if (key% 2 = = 0) {            System.out.println ("to delete key" + key);                 Map.Remove (key);                 System.out.println ("the key" + + key + "was deleted");             }        }         SYSTEM.OUT.PRINTLN ("Map size =" + map.size ());        For (Map.entry<integer, string> entry:map.entrySet ()) {            System.out.println (Entry.getkey () + "=" + Entry.getvalue ());}}}    

The output of the above code is

To delete key 0The key 0 is deletedexception in thread "main" Java.util.ConcurrentModificationExceptionat Java.util.HashM Ap$hashiterator.nextentry (hashmap.java:793) at Java.util.hashmap$entryiterator.next (HashMap.java:834) at Java.util.hashmap$entryiterator.next (hashmap.java:832) at Com.gpzuestc.collection.MapIteratorTest.main ( MAPITERATORTEST.JAVA:60)

The above output can be used to find that the first even key element has been successfully removed, and the exception is thrown at the time the iterator traverses the next element.

If you replace the above highlighted traversal code with keyset, the remove operation through keyset also throws an exception when traversing the next element, such as the following.

set<integer> KeySet = Map.keyset ();        for (Integer key:keyset) {            if (key% 2 = = 0) {                System.out.println ("to delete key" + key);                Keyset.remove (key);                System.out.println ("the key" + + key + "was deleted");             }        }

 

To delete key 0The key 0 is deletedexception in thread "main" Java.util.ConcurrentModificationExceptionat Java.util.HashM Ap$hashiterator.nextentry (hashmap.java:793) at Java.util.hashmap$keyiterator.next (HashMap.java:828) at Com.gpzuestc.collection.MapIteratorTest.main (mapiteratortest.java:49)

If you want to implement a remove operation during traversal, neither of the above can be used, but it needs to be achieved by displaying a iterator that gets keyset or entryset.

Iterator<map.entry<integer, string>> it = Map.entryset (). Iterator ();        while (It.hasnext ()) {            Map.entry<integer, string> Entry = It.next ();            Integer key = Entry.getkey ();            if (key% 2 = = 0) {           System.out.println ("to delete key" + key);           It.remove ();               System.out.println ("the key" + + key + "was deleted");             }        }
To delete key 0The key 0 is deletedto delete key 2The key 2 was deletedto delete key 4The key 4 is deletedto delete key 6The Key 6 was deletedto delete key 8The key 8 is deletedmap size = Wuyi = Value13 = value35 = Value57 = Value79 = Value9
Analysis Reason

In fact, the above three traversal methods are basically used iterators, the reason for the different results is due to the implementation of the remove operation different decision.

First both methods throw an exception in the same place where the NextEntry method is called

Final entry<k,v> NextEntry () {            if (modcount! = expectedmodcount)                throw new Concurrentmodificationexception ();            Entry<k,v> e = next;            ...            ...     }

The modcount here is to indicate that the elements in the map have been modified several times (this value will increment when new elements are removed), whereas Expectedmodcount is the desired number of modifications, which are equal at the time of construction of the iterator. If these two values appear out of sync during the traversal, the concurrentmodificationexception exception is thrown.

1, HashMap the Remove method implementation

Public V Remove (Object key) {    entry<k,v> e = Removeentryforkey (key);    return (E = = null? null:e.value);}

2, Hashmap.keyset the Remove method implementation

public boolean remove (Object o) {    return HashMap.this.removeEntryForKey (o) = null;}

3, Hashmap.hashiterator the Remove method implementation

public void Remove () {   if (current = = null)        throw new IllegalStateException ();   if (modcount! = expectedmodcount)        throw new Concurrentmodificationexception ();   Object k = Current.key;   current = null;   HashMap.this.removeEntryForKey (k);   Expectedmodcount = Modcount;}

The above three implementations are implemented by calling the Hashmap.removeentryforkey method to remove key. In the Removeentryforkey method, as long as you remove the key Modcount will perform a self-increment operation, at this time Modcount and expectedmodcount inconsistent, the above three remove implementations, Only the third iterator remove method synchronizes the Expectedmodcount value with Modcount after the Removeentryforkey method is called, so when the next element is traversed to invoke the NextEntry method, The iterator method does not throw an exception.

Final entry<k,v> Removeentryforkey (Object key) {        int hash = (key = = null)? 0:hash (Key.hashcode ());        int i = indexfor (hash, table.length);        Entry<k,v> prev = table[i];        entry<k,v> e = prev;         while (E! = null) {            entry<k,v> next = e.next;            Object K;            if (E.hash = = Hash &&                (k = e.key) = = Key | | (Key! = null && key.equals (k)))) {                modcount++;                size--;                if (prev = = e)                    table[i] = next;                else                    prev.next = next;                E.recordremoval (this);                return e;            }            prev = e;            e = next;        }         return e;    }
Divergence

1. What if the data is added or modified during traversal?
Adding or modifying data can only be done through the put method of the map, modifying the data during traversal, but adding a new key will throw an exception at the next loop, because Modcount will also increment when the new key is added.

2, some collection classes also have the same traversal problem, such as ArrayList, through the iterator way can be properly traversed to complete the remove operation, directly call the list of the Remove method will throw an exception.

Will throw Concurrentmodificationexception exception for (String str:list) {list.remove (str);}//Correct traversal removal method iterator<string> it = List.iterator (); while (It.hasnext ()) {it.next (); It.remove ();}

3. Why is the JDK designed so that only the remove operation is allowed through iterator?
The Remove method of both HashMap and keyset can remove any element by passing the key parameter, and iterator can only delete the current element, once the deleted element is the iterator object in which next is being referenced, If you fail to throw an exception by Modcount, Expectedmodcount comparison, the next loop will be the current point, and iterator will traverse a removed expired data.

Java Traversal HashMap and modify (remove) (reprint)

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.