There are many ways to traverse and delete elements in List or Map, and problems will arise when used improperly. Let’s learn from this article below.
1. Delete elements during List traversal
Using index subscript traversal
Example: Delete 2 in 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 result:
1234list=[1, 2, 3, 4]
question:
The result shows that only one 2 was deleted, and the other 2 was missed. The reason is: after deleting the first 2, the number of elements in the set is reduced by 1, and the subsequent elements are moved forward by 1 bit, resulting in the second 2 being missed.
How to use 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(value); } System.out.println("list=" + list.toString()); }result:
Exception in thread "main" 12java.util.ConcurrentModificationException at java.util.ArrayList$Ittr.checkForComodification(Unknown Source) at java.util.ArrayList$Ittr.next(Unknown Source) at test.ListIterator.listIterator2(ListIterator.java:39) at test.ListIterator.main(ListIterator.java:10)
illustrate:
Description of ConcurrentModificationException in jdk:
public class ConcurrentModificationException extends
RuntimeException This exception is thrown when the method detects concurrent modification of the object but does not allow such modification.
For example, when a thread iterates on a Collection, another linear modification is usually not allowed to be made. Usually in these cases, the results of the iteration are uncertain. If this behavior is detected, some iterator implementations (including all general collection implementations provided by JRE) may choose to throw this exception. The iterator that performs this operation is called a fast failure iterator because the iterator fails very quickly without risking the risk of arbitrary uncertain behavior at some time in the future.
Note : This exception does not always indicate that the object has been modified concurrently by a different thread. If a single thread issues a sequence of method calls that violates the object's contract, the object may throw this exception. For example, if a thread directly modifies the collection when iterates on the collection using a fast fail iterator, the iterator will throw this exception.
Note : The fast failure behavior of the iterator cannot be guaranteed, because generally, it is impossible to make any hard guarantees on whether there are any out-of-synchronous concurrent modifications. A quick failure operation will do its best to throw ConcurrentModificationException . Therefore, it is wrong to write a program that depends on this exception to improve the correctness of such operations. The correct way is: ConcurrentModificationException should be used only to detect bugs.
For each in Java actually uses iterator for processing. Iterator does not allow collections to be deleted during the use of iterator. This causes the 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(value); } System.out.println("list=" + list.toString()); }result:
12234list=[1, 3, 4]
2. Delete elements during Map traversal
Examples of correct 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"); //Full traversal of Map for (Entry<String, String> entry : map.entrySet()) { System.out.printf("key: %s value:%s/r/n", entry.getKey(), entry.getValue()); } //Delete the element 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(); } } //Full traverse Map for (Entry<String, String> entry: map.entrySet()) { System.out.printf("key: %s value:%s/r/n", entry.getKey(), entry.getValue()); }}result:
key: 1 value:test1key: 2 value:test2key: 3 value:test3key: 4 value:test4delete key:1 value:test1delete key:3 value:test3key: 2 value:test2key: 4 value:test4
Notice
But there are also things we need to pay attention to about remove() method of iterator:
The remove() iterator.next() () method is called.
Before calling the remove() method, next() method must be called once.
Description of the remove() method in JDK-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 next. If the iterator is modified in a way other than calling this method when iterating, the iterator's behavior is ambiguous.
Throws: UnsupportedOperationException - if the iterator does not support remove operation. IllegalStateException - If the next method has not been called, or the remove method has been called after the last call to the next method.
Summarize
The above is all about deleting elements during the traversal of List and Map. I hope that the content of this article will be of some help to everyone's study or work. If you have any questions, you can leave a message to communicate.