In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
How to delete while traversing the java collection class? in view of this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
Delete operation 1. 1 while traversing java collection classes. Background
When traversing data using java's collection class, some data may need to be deleted in some cases. Often if you operate improperly, you will throw a ConcurrentModificationException. We will briefly explain the examples of errors, as well as some correct actions and a simple analysis of the reasons.
P.S. The sample code and analysis are for the instance class ArrayList of List, and other collection classes can be used as a reference.
two。 Code example
The sample code is as follows, and which action is correct can be explained by comments:
Public class TestIterator {public static void main (String [] args) {List list = new ArrayList (); list.add ("1"); list.add ("2"); list.add ("3"); list.add ("4"); list.add ("5"); print (list) / / Operation 1: error demonstration without triggering ConcurrentModificationException System.out.println ("NO.1"); List list1 = new ArrayList (list); for (String str:list1) {if ("4" .equals (str)) {list1.remove (str);}} print (list1) / / Operation 2: error demonstration, using for each to trigger ConcurrentModificationException System.out.println ("NO.2"); try {List list2 = new ArrayList (list); for (String str:list2) {if ("2" .equals (str)) {list2.remove (str) }} print (list1);} catch (Exception e) {e.printStackTrace ();} / / Operation 3: error demonstration, trigger ConcurrentModificationException try {System.out.println ("NO.3") using iterator; List list3 = new ArrayList (); Iterator iterator3 = list3.iterator () While (iterator3.hasNext ()) {String str = iterator3.next (); if ("2" .equals (str)) {list3.remove (str);}} print (list3);} catch (Exception e) {e.printStackTrace () Operation 4: operate System.out.println ("NO.4") correctly; List list4 = new ArrayList (list); for (int I = 0; I)
< list4.size(); i++) { if ("2".equals(list4.get(i))) { list4.remove(i); i--; // 应当有此操作 } } print(list4); // 操作5: 正确操作 System.out.println("NO.5"); List list5 = new ArrayList(list); Iterator iterator = list5.iterator(); while (iterator.hasNext()) { String str = iterator.next(); if ("2".equals(str)) { iterator.remove(); } } print(list5); } public static void print(List list) { for (String str : list) { System.out.println(str); } }} P.S. 上面的示例代码中,操作1、2、3都是不正确的操作,在遍历的同时进行删除,操作4、5能达到预期效果,推建使用第5种写法。 3. 分析 首先,需要先声明3个东东: 1. for each底层采用的也是迭代器的方式(这个我并没有验证,是查找相关资料得知的),所以对for each的操作,我们只需要关注迭代器方式的实现即可。 2. AraayList底层是采用数组进行存储的,所以操作4实现是不同于其它(1、2、3、5)操作的,他们用的都是迭代器方式。 3. 鉴于1、2点,其实本文重点关注的是采用迭代器的remove(操作5)为什么没有问题,而采用集合的remove(操作1、2、3)就不行。 3.1 为什么操作4没有问题 // 操作4: 正确操作 System.out.println("NO.4"); List list4 = new ArrayList(list); for(int i = 0; i < list4.size(); i++) { if ("2".equals(list4.get(i))) { list4.remove(i); i--; // 应当有此操作 } } 这个其实没什么太多说的,ArrayList底层采用数组,它删除某个位置的数据实际上就是把从这个位置下一位开始到最后位置的数据在数组里整体前移一位(基本知识,不多说明)。所以在遍历的时候,重点其实是索引值的大小,底层实现是需要依赖这个索引 的,这也是为什么最后有个i--,因为我们删除2的时候,索引值i为1,删除的时候,就把索引为2到list.size()-1的数据都前移一位,如果不把i-1,那么下一轮循环时,i的值就为2,这样就把原来索引值为2,而现在索引值为1的数据给漏掉了,这个地方需要注意一下。比如,如果原数据中索引1、2的数据都为2,想把2都删除掉,如果不进行i--,那么把索引1处的2删除掉后,下一次循环判断时,就会把原来索引为2,现在索引为1的这个2给遗漏掉了。 3.2 采用迭代时ConcurrentModificationException产生的原因 其实这个异常是在迭代器的next()方法体调用checkForComodification()时抛出来的: 看下迭代器的这两个方法的源码: public E next() { checkForComodification();//注意这个方法,会在这里抛出 int i = cursor; if (i >} final void checkForComodification () {/ / the problem lies in the values of modCount and expectedModCount if (modCount! = expectedModCount) throw new ConcurrentModificationException ();}
1. First of all, the value of modCount is a variable of ArrayList, while expectedModCount is a variable of iterator.
ModCount: this value is a self-increment operation when the structure of the collection changes (such as add, delete, etc.). In fact, in ArrayList, this value changes only when the element is deleted.
ExpectedModCount: this value assigns the value of modCount to the iterator's variable expectedModCount when calling the collection's iterator () method to instantiate the iterator. That is, during the iteration of the iterator, the value of expectedModCount does not change after initialization, while the value of modCount may change (such as a delete operation), which is why the two values are compared each time the next () method is called.
In fact, I understand them as similar to the implementation of CAS theory, in fact, when the iterator traverses the remove method of the collection, the code looks serial, but it can be thought of as two different threads operating this ArrayList object in parallel (I tried to understand it this way after looking at other materials, too).
3.3.Why is there no problem using iterator remove when traversing
According to Article 3.2, we know that since the reason for the occurrence of ConcurrentModificationException in the remove method of ArrayList lies in the values of modCount and expectedCount, the problem is very clear. First, take a look at the source code of the iterator's remove method:
Public void remove () {if (lastRet < 0) throw new IllegalStateException () / / although this method is also called here, we can ignore it this time, because the remove () method is / / iterator itself, that is, it can be seen that traversal and deletion occur serially, and we have not yet started to remove / / operation, so the check here should not throw an exception, if ConcurrentModificationException is thrown / / that can only be caused by other threads changing the structure of the current collection, not because we have not yet started the removal operation checkForComodification () Try {/ / remove ArrayList.this.remove (lastRet); cursor = lastRet; lastRet =-1; / / re-assign, using expectedModCount to keep the values consistent with modCount values expectedModCount = modCount } catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException ();}}
Note that when calling the iterator's remove method, you are also calling the collection's remove method, but because the data consistency between modCount and expectedModCount is maintained here, ConcurrentModificationException will not be thrown the next time the next () method is called and the checkForComodification method is called.
3.4Why Operation 1 did not throw ConcurrentModificationException
In fact, operation 1 uses for each, but as mentioned above, the bottom layer is still an iterator, which is an iterator, but the collection's remove method does not throw ConcurrentModificationException, because the removed element is the penultimate element.
When the iterator iterates, the hasNext () method is called to determine whether to end the iteration, and if not, the next () method is called to get the next element, and when the next () method is called, ConcurrentModificationException is thrown when the checkForComodification method is called.
Since there is one last element, why does the loop end? the problem lies in the hasNext () method. Take a look at the source code:
Public boolean hasNext () {return cursor! = size;}
In fact, every time you call the next () method iteration, cursor will add a cursor equivalent to a cursor, when it is not equal to the size of the collection size, it will always loop, but because operation 1 removes an element, resulting in the collection size minus one, resulting in the call to the hasNext () method, the end of the loop, will not traverse the last element, there will be no later problems.
A remove data trap in the java collection traverses the collection itself and deletes the traversed data at the same time
When using the Set collection: an exception occurs when traversing the collection itself while deleting the traversed data
Iterator it = atomSet.iterator (); while (it.hasNext ()) {if (! vars.contains (it.next () {atomSet.remove (it.next ());}}
Throw an exception:
Exception in thread "main" java.util.ConcurrentModificationException
At java.util.HashMap$HashIterator.nextEntry (HashMap.java:793)
At java.util.HashMap$KeyIterator.next (HashMap.java:828)
At test2.Test1.main (Test1.java:16)
The essential cause of anomaly
Iterator works in a separate thread and has a mutex lock. After Iterator is created, a single-linked index table pointing to the original object will be created. When the number of objects changes, the contents of the index table will not change synchronously, so when the index pointer moves backward, you will not find the object to be iterated, so according to the fail-fast principle, Iterator will immediately throw a java.util.ConcurrentModificationEx ception exception.
So Iterator does not allow iterated objects to be changed while working. However, you can use Iterator's own method remove () to delete objects, and the Iterator.remove () method will maintain index consistency while deleting the current iterative object.
Solve
Using the remove method of Iterator
Iterator it = atomVars.iterator (); while (it.hasNext ()) {if (! vars.contains (it.next () {it.remove ();}}
The code executes normally.
This is the answer to the question about how to delete the java collection class while traversing. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel to learn more about it.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.