How does Java delete elements during List or Map traversal

  • 2020-05-19 04:53:32
  • OfStack

There are many ways to iterate through and remove elements from List or Map, which can cause problems when used incorrectly. Learn again with this article.

1. Delete elements during List traversal

Traversal using index subscripts

Example: delete 2 from the list


public static void main(String[] args) {
  List<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(4);
  
  for (int i = 0; i < list.size(); i++) {
   if(2 == list.get(i)){
    list.remove(i);
   }
   System.out.println(list.get(i));
  }
  
  System.out.println("list=" + list.toString());
  
 }

Output results:


1
2
3
4
list=[1, 2, 3, 4]

Question:

The result shows that only one 2 was deleted, and the other 2 was omitted. The reason is that after the first 2 was deleted, the number of elements in the set was reduced by 1, and the subsequent elements were moved forward by 1 bit, resulting in the omission of the second 2.

Use For for loop traversal

Example:


public static void listIterator2(){
  List<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(4);
  
  for (int value : list) {
   if(2 == value){
    list.remove(value);
   }
   System.out.println(value);
  }
  
  System.out.println("list=" + list.toString());
  
 }

Results:


Exception in thread "main" 1
2
java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
 at java.util.ArrayList$Itr.next(Unknown Source)
 at test.ListIterator.listIterator2(ListIterator.java:39)
 at test.ListIterator.main(ListIterator.java:10)

Description:

Description of ConcurrentModificationException in jdk:

public class ConcurrentModificationException extends

RuntimeException throws this exception when a method detects concurrent changes to an object but does not allow such changes.

For example, when a thread iterates over an Collection, another linear modification of that Collection is usually not allowed. Often in these cases, the outcome of an iteration is uncertain. If this behavior is detected, some iterator implementations (including all common collection implementations provided by JRE) may choose to throw this exception. The iterator that performs this operation is called a quick-fail iterator, because the iterator fails completely quickly, without the risk of arbitrary uncertain behavior at some point in the future.

Note: this exception does not always indicate that the object has been modified concurrently by different threads. If a single thread issues a sequence of method calls that violates an object's protocol, the object may throw this exception. For example, if the thread directly modifies the collection while iterating over the collection using a quick-fail iterator, the iterator throws this exception.

Note: the quick failure behavior of an iterator cannot be guaranteed, because 1 in general, it is not possible to make any hard and fast guarantees about asynchronous concurrent changes. A quick fail operation is thrown as best it can ConcurrentModificationException . Therefore, it is a mistake to write a program that relies on this exception to improve the correctness of such an operation. The correct approach is: ConcurrentModificationException It should only be used to detect bug.

For each in Java actually USES iterator for processing. While iterator does not allow collections to be deleted during the use of iterator. So that causes iterator to throw ConcurrentModificationException .

The right way

Example:


public static void listIterator3(){
  List<Integer> list = new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(2);
  list.add(3);
  list.add(4);
  
  Iterator<Integer> it = list.iterator();
  while (it.hasNext()){
   Integer value = it.next();
   if (2 == value) {
    it.remove();
   }
   
   System.out.println(value);
  }
  
  System.out.println("list=" + list.toString());
 }

Results:


1
2
2
3
4
list=[1, 3, 4]

2. Delete elements during Map traversal

Examples of the right approach:


public static void main(String[] args) {
 HashMap<String, String> map = new HashMap<String, String>();
 map.put("1", "test1");
 map.put("2", "test2");
 map.put("3", "test3");
 map.put("4", "test4");
 
 // Complete traverse Map
 for (Entry<String, String> entry : map.entrySet()) {
  System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue());
 }
 
 // Remove elements 
 Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); 
 while(it.hasNext())
 { 
  Map.Entry<String, String> entry= it.next(); 
  String key= entry.getKey(); 
  int k = Integer.parseInt(key);
  if(k%2==1)
  { 
   System.out.printf("delete key:%s value:%s\r\n", key, entry.getValue());
   it.remove(); 
  } 
 } 
 
 // Complete traverse Map
 for (Entry<String, String> entry : map.entrySet()) {
  System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue());
 }
}

Results:


key: 1 value:test1
key: 2 value:test2
key: 3 value:test3
key: 4 value:test4
delete key:1 value:test1
delete key:3 value:test3
key: 2 value:test2
key: 4 value:test4

Pay attention to

But for iterator remove() Methods, we also need to pay attention to:

Once per call iterator.next() Method, which can only be called once remove() Methods.

call remove() Method must be called once before next() Methods.

Description of the remove() method in es1064en-API:

void remove() Removes the last element returned by the iterator from the collection pointed to by the iterator (optional operation). This method can only be called once per call to next. If the collection that the iterator points to is modified in a way other than by calling this method when iterating, the iterator's behavior is not clear.

Throws: ConcurrentModificationException0 - if the iterator is not supported remove Operation. IllegalStateException - if not already called next Method, or called the last time next Method has been called since remove Methods.

conclusion

The above is all about List and Map to delete the elements in the process of traversing, I hope the content of this article can bring you a certain help in your study or work, if you have any questions, you can leave a message to communicate.


Related articles: