package com.test.io; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.LinkedList; import com.mysql.jdbc.Buffer; public class ReadKeyFile { public static void main(String[] args) throws IOException { BufferedReader bufferedReader=null; try { bufferedReader = new BufferedReader(new FileReader("C:/Users/Administrator/Desktop/test.txt")); LinkedList<String> list = new LinkedList<String>(); String str=bufferedReader.readLine(); while((str=bufferedReader.readLine())!=null) { System.out.println(str); list.add(str); } System.out.println("------------"); for (String string : list) { System.out.println(list.removeLast()); } } catch (Exception e) { e.printStackTrace(); } finally { if(bufferedReader != null) bufferedReader.close(); } } }
结果及报错:
22222222222222222222 33333333333333333333 44444444444444444444 55555555555555555555 66666666666666666666 77777777777777777777 ------------ 77777777777777777777 java.util.ConcurrentModificationException at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) at java.util.LinkedList$ListItr.next(LinkedList.java:888) at com.test.io.ReadKeyFile.main(ReadKeyFile.java:24)
test.txt:
11111111111111111111 22222222222222222222 33333333333333333333 44444444444444444444 55555555555555555555 66666666666666666666 77777777777777777777
如果将源代码红色部分替换为以下,则可以正常输出,可见问题并不在remveLast()方法,而在迭代。
System.out.println(list.removeLast()); System.out.println(list.removeLast());
在网上查到一段文字:
1.在使用增强for循环进行集合的迭代的时候其实默认使用的是迭代器;2.因此在循环中不能使用集合的引用变量直接操作集合,避免导致多线程并发访问的安全性异常。
1的意思即增强for循环的遍历方式类似与:
Iterator<String> iterator = list.iterator(); while(iterator.hasNext()) System.out.println(iterator.next());
鉴于此,有必要看一下LinkedList的代码。在LinkedList中,这个iterator就是ListItr ,它是继承自Itr类,next()方法正是出自Itr类,在里面找到next()的源码如下:
public E next() { checkForComodification(); try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }
注意checkForComodification(),这就是报错的地方啦,具体是在下面这个地方报的错:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
根据我们的测试:LinkedList打印出第一排7就报错了。
modCount 这个在打应出第一排7之后的值应该为8,因为add了7次,又removeLast了一次嘛
那expectedModCount为多少呢?
看看Itr源代码吧,真乱,又实在是不想去读注释,我还是去翻翻JAVA编程思想先。
好吧,翻了一下书没翻到,百度了一下,又重新看了下代码,继续上面的问题,expectedModCount的值。
expectedModCount的值在removeLast之后为7。因为add里面有expectedModCount=modCount这样的语句,而removeLast里面没有。
这样的机制,应该是为了检测一边迭代,一边修改集合的危险操作。