ConcurrentModificationException
在使用List.subList()取得subList后,可以使用subList修改List中的元素,但是如果List中做了修改操作,那么就不能再操作subList了(查询操作也不行),否则将报ConcurrentModificationException。因为List中有个modCount的字段,List每次有修改操作,modCount都会自增。而subList每个操作前都要判断自己的modCount与List的modCount是否相等,不等则报ConcurrentModificationException。修改subList,subList会调用List去执行修改,subList再同步List的modCount;而List修改时,不会去修改subList的信息,如size,modCount等。所以再List修改后,原来的subList需要重新获取。
例子:
List<Gerbil> list = new LinkedList<Gerbil>();
for(int i=10; i>0; i--){
list.add(new Gerbil());
}
println(list.toString());
List subList = list.subList(0,5);
println(subList.toString());
list.removeAll(subList);
// list.remove(0);
// subList.remove(1);
println(list.toString());
这个例子非常特别,看似list修改后,没有对subList操作。但是再list移除时,会调用subList.contains(),然后调用iterator(),就会检查modCount。
在使用Iterator过程中,也会报ConcurrentModificationException,直接原因也是因为modCount不一致,因为Collection中并没有Iterator的引用,所以Collection修改后,其modCount自增,而Iterator中的modCount未变,导致Iterator检查modCount是否一致时报错。那根本原因是如果Collection中变化了,而Iterator中的信息与Collection不一致,会导致一些问题。比如在iterator.hasNext执行后,Collection删除了一些元素,很可能导致在iterator.next时访问越界。
List<Gerbil> list = new LinkedList();
for(int i=10; i>0; i--){
list.add(new Gerbil());
}
//foreach语句也是使用iterator的,所以以下操作也会导致报错
// for(Gerbil g : list){
// g.hop();
// list.remove(g);
// }
Iterator<Gerbil> iterator = list.iterator();
while (iterator.hasNext()){
Gerbil g = iterator.next();//会去检查modCount
g.hop();
list.remove(6);//将导致下一个循环周期报错
}
List容器特有的ListIterator
可前后移动,可通过set()改变当前cursor指向的元素,还有add()。创建时可通过int指定开始cursor。下面的例子时将sourceList中的元素反序放在targetList中,注意向listIterator(index)传入的index,如果从后向前遍历,传入的参数时lsit.size(),而从前向后遍历时,是传入0。在调用previous()时,是先减1后再获取元素的,而调用next()时是先获取元素再加1的。
List<Gerbil> sourceList = new ArrayList<Gerbil>(10);
List<Gerbil> targetList = new ArrayList<Gerbil>();
for(int i=10; i>0; i--){
sourceList.add(new Gerbil());
}
targetList.addAll(sourceList);
ListIterator<Gerbil> sourceIterator = sourceList.listIterator(0);
ListIterator<Gerbil> targetIterator = targetList.listIterator(targetList.size());
while (sourceIterator.hasNext() && targetIterator.hasPrevious()){
targetIterator.previous();
targetIterator.set(sourceIterator.next());
}
println(sourceList.toString());
println(targetList.toString());
ListIterator的add()和remove(),nextIndex()和previousIndex()
Iterator中有一个index表明当前索引(虽然LinkedList不是使用数组实现,但是仍然可是使用索引),调用next会返回index指向的元素,然后index++;调用previous会index--,然后返回index指向的元素。如果使用add(object),则object插入到index的位置,原来index及其后的元素后移一位,然后index++;调用remove(),则移除index位置的元素,然后index后面的元素前移一位;调用nextIndex(),返回index;调用previousIndex(),返回index-1;