基础类
package com.yh.container;
public class Student {
private String sno;
private String name;
private int age;
private String sex;
public Student(String sno,String name,int age,String sex){
this.sno=sno;
this.name=name;
this.age=age;
this.sex=sex;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAge(int age) {
this.age = age;
}
//重写 :继承关系, 子类重写父类的方法
@Override
public boolean equals(Object obj){
//obj 和当前对象指向同一块内存
if(obj==this){
return true;
}
if(obj==null){
return false;
}
/* if(this.getClass()==obj.getClass()){
}*/
//两个对象是同一个实例,实例的所有属性值相等
if(obj instanceof Student){
Student stu=(Student)obj;
if(stu.getSno()!=null && this.sno.equals(stu.getSno()) && stu.getName()!=null && this.name.equals(stu.getName()) && this.age==stu.getAge()){
return true;
}
}
return false;
}
//重写hashcode
@Override
public int hashCode(){
return sno.hashCode()+name.hashCode()+String.valueOf(age).hashCode();
}
}
package com.yh.container;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
* Collection 是根接口 List,Set子接口
* List 子类:ArrayList,Vector,LinkedList
*
* Collection对象的创建,通过子类
* collection 常用方法:
* boolean add(Object object) 在集合末尾添加元素
*
* boolean contains(Object o) 如果此 collection 包含指定的元素,则返回 true。
boolean isEmpty() 判断容器是否为空
boolean remove(Object o) 从容器删除制定的元素
boolean clear() 删除容器中所有的元素
int size() 返回容器中元素的个数
Iterator iterator() 迭代器 对容器中的元素进行迭代
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
E next() 返回迭代的下一个元素。
*/
public class TestCollection01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建Collection对象
Collection collection=new ArrayList();
int a=10;
String str1="hello Word!";
boolean flag=true;
Student zhangsan=new Student("10001","张三",23,"男");
//add()方法,添加元素
collection.add(10);
collection.add(str1);
collection.add(flag);
collection.add(zhangsan);
//contains(Object object) 是否包含指定的元素
System.out.println("是否包含hello Word!="+collection.contains("hello Word!"));
System.out.println("是否包含true="+collection.contains(true));
System.out.println("是否包含Integer(10)="+collection.contains(new Integer(10)));
System.out.println("是否包含张三="+collection.contains(new Student("10001","张三",23,"男")));
System.out.println("删除之前容器是否为空:"+collection.isEmpty());
System.out.println("删除前容器中元素个数:"+collection.size());
//remove 删除元素
/* System.out.println("删除元素:"+collection.remove(new Integer(10)));
collection.remove("hello Word!");
collection.remove(true);
collection.remove(new Student("10001","张三",23,"男"));
*/
//isEmpty() 判断容器是否为空
System.out.println("删除之后容器是否为空:"+collection.isEmpty());
//size() 返回容器中元素个数
System.out.println("删除后容器中元素个数:"+collection.size());
//清空容器中所有的元素
// collection.clear();
//Iterator 迭代器堆collection中元素进行迭代 hasNext() next()
Iterator it=collection.iterator();
while(it.hasNext()){
System.out.println("迭代:"+it.next());
}
}
}
package com.yh.container;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
* Colelction 高级方法
* boolean addAll(Collection c) 往此 collection 容器添加指定容器c中所有的元素
* boolean containsAll(Collection c) 如果此 collection 包含指定 collection c中的所有元素,则返回 true。
* boolean removeAll(Collection c) 删除此 collection 中那些也包含在指定 collection c 中的所有元素
boolean retainAll(Collection c) 仅保留此 collection 中那些也包含在指定 collection c的元素
*/
public class TestCollection02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Collection collection1=new ArrayList();
collection1.add("高子超");
collection1.add("高可超");
collection1.add("朱豪杰");
System.out.println("容器1元素个数:"+collection1.size());
Collection collection2=new ArrayList();
collection2.add("李宁");
collection2.add("王毅");
collection2.add("李昂");
//addAll(Collection c)
collection1.addAll(collection2);
Iterator it=collection1.iterator();
while(it.hasNext()){
System.out.println("容器1元素:"+it.next());
}
Collection collection3=new ArrayList();
collection3.add("高子超");
collection3.add("高可超");
collection3.add("王文光");
//collection3.add("朱豪杰");
System.out.println("collection1 是否包含collection3所有元素:"+collection1.containsAll(collection3));
Collection collection4=new ArrayList();
collection4.add("高子超");
collection4.add("高可超");
collection4.add("王文光");
collection1.removeAll(collection4);
Iterator it2=collection1.iterator();
while(it2.hasNext()){
System.out.println("容器1删除容器4中所有的元素:"+it2.next());
}
Collection collection5=new ArrayList();
collection5.add("李昂");
collection5.add("高可超");
collection1.retainAll(collection5);
Iterator it3=collection1.iterator();
while(it3.hasNext()){
System.out.println("容器只保留容器collection5中所有的元素:"+it3.next());
}
}
}
package com.yh.container;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
* List :动态数组 实现类:ArrayList,Vector,LinkedList
* list 集合的特性:元素可重复,且有序,元素可以为null
* 独有的方法:
* get(index x) 根据索引取值
* Itertor iterator() 迭代器遍历,但不能修改元素
* for循环,
* set(int index,Value value) 用指定的元素替代此列表中指定位置上的元素。
*
* int indexOf(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
int lastIndexOf(object o) 返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。
remove(Object obj) 移除此列表中首次出现的指定元素
remove(index inx) 移除此列表中指定位置上的元素
*/
public class TestList03 {
public static void main(String[] args) {
// TODO Auto-generated method stub
List list=new ArrayList();
list.add(10);
list.add("Tom");
list.add(true);
list.add("hello");
list.add(10);
list.add("Tom");
list.add(null);
System.out.println("元素个数:="+list.size());
//获取第一个元素
System.out.println(list.get(0));
//获取最后一个元素
System.out.println(list.get(list.size()-1));
//迭代器遍历list
Iterator it=list.iterator();
while(it.hasNext()){
System.out.println("元素:"+it.next());
}
list.set(0, 100);
//for循环遍历
for(int i=0;i<list.size();i++){
System.out.println("循环遍历元素:"+list.get(i));
}
//增强for循环
for(Object obj : list){
System.out.println("增强for遍历元素:"+obj);
}
//"hello"在list首次出现的位置,返回 索引
System.out.println(list.indexOf("hello"));
//
System.out.println("Tom在list首次出现的位置 :"+list.indexOf("Tom"));
System.out.println("Tom在list最后出现的位置 :"+list.lastIndexOf("Tom"));
System.out.println("Tom在list最后出现的位置 :"+list.lastIndexOf("tom"));
System.out.println("删除Tom前元素个数 :"+list.size());
//根据指定的元素删除
/* list.remove("Tom");
//根据索引删除元素
list.remove(list.lastIndexOf("Tom"));
System.out.println("删除Tom后元素个数 :"+list.size());*/
//查找容器中是否由Tom,换成Lucy
for(int i=0;i<list.size();i++){
if(list.get(i)!=null && list.get(i).equals("Tom")){
list.set(i, "Lucy");
}
if(list.get(i)==null){
list.set(i, "");
}
}
for(Object obj : list){
System.out.println("Tom换成Lucy:"+obj);
}
}
}
package com.yh.container;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
/**
* Set接口 :元素无序,且元素不可重复, 允许使用 null 元素 实现类:HashSet,TreeSet,LinkedHashSet
* HashSet实例化 new HashSet()
*add() 添加元素
*
*遍历 :Iterator iterator() HashSet类中没有提供根据集合索引获取索引对应的值的方法, 因此遍历HashSet时需要使用Iterator迭代器
*
*TreeSet 字母的自然顺序排列
*LinkedHashSet 元素添加时的顺序
*
*/
public class TestSet07 {
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet hashSet=new HashSet();
hashSet.add(10);
hashSet.add(true);
hashSet.add(new Person("张三",21));
hashSet.add(10);
hashSet.add(null);
hashSet.add(new Person("张三",21));
System.out.println(hashSet.size());
Iterator it=hashSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
TreeSet set = new TreeSet();
set.add("kkkkk");
set.add("ddddd");
set.add("vvvvv");
set.add("eeeee");
set.add("kkkkk");
System.out.println(set);
}
}
package com.yh.container;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
* Map 接口 Map中以键-值对 形式存储数据 实现类 : HashMap,Properties,HashTable
* 键 不可以重复,值可以重复
* put(Object key, Object value)
* get(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
* remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
* boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。
int size() 返回此映射中的键-值映射关系数。
* Collection<V> values() 返回此映射中包含的值的 Collection 视图。
* Set keySet() 返回此映射中包含的键的 Set 视图。
* Set entrySet() 返回此映射中包含的映射关系(key-value)的 Set 视图。
*
* boolean isEmpty() 如果此映射未包含键-值映射关系,则返回 true。
*/
public class Test08Map {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map map=new HashMap();
System.out.println("map 集合是否为空:"+map.isEmpty());
map.put("lucy", 12522252552l);
map.put("10001", new Person("Tom",20));
map.put("10002", new Person("Tom",20));
map.put("10002", new Person("jack",21));
map.put(1, "张三");
System.out.println("map 集合是否为空:"+map.isEmpty());
//key-value 个数
System.out.println("键值对个数 :"+map.size());
System.out.println(map.get(1));
System.out.println(map.get("lucy"));
System.out.println(map.get("10001"));
System.out.println(map.get(2)); //不包含该键的映射关系,则返回 null
System.out.println("map集合是否包含10001的key:"+map.containsKey("10001"));
System.out.println("map集合是否包含10002的key:"+map.containsKey("10002"));
System.out.println("map集合是否包含张三的value:"+map.containsValue("张三"));
System.out.println("map集合是否包含Tom的value:"+map.containsValue(new Person("Tom",20)));
//对Map的value进行遍历
Collection cl1=map.values();
Iterator it=cl1.iterator();
while(it.hasNext()){
System.out.println("map 的Value集合元素 :"+it.next());
}
//对Map的Key进行遍历
Set set=map.keySet();
Iterator it2=set.iterator();
while(it2.hasNext()){
System.out.println("map 的key集合元素 :"+it2.next());
}
/* //把名字叫"张三"的人删除掉
Set deleteZhangsan=map.keySet();
Iterator itTemp=deleteZhangsan.iterator();
while(itTemp.hasNext()){
Object key=itTemp.next();
//根据key 获取value 判断value值是否是"张三"
if(map.get(key).equals("张三")){
//删除"张三"对应的key
// map.remove(key);
// return
}
}*/
//堆map 的key-value 进行迭代
Set setKeyValue=map.entrySet();
Iterator it3=setKeyValue.iterator();
while(it3.hasNext()){
System.out.println("map 的key-value映射:"+it3.next());
}
}
}
根本原因
以上都有3种出现异常的情况有一个共同的特点,都是使用Iterator进行遍历,且都是通过ArrayList.remove(Object) 进行删除操作。
想要找出根本原因,直接查看ArrayList源码看为什么出现异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | public class ArrayList<e> extends AbstractList<e> implements Cloneable, Serializable, RandomAccess {
@Override public boolean remove(Object object) { Object[] a = array; int s = size; if (object != null) { for (int i = 0; i < s; i++) { if (object.equals(a[i])) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 只要删除成功都是累加 return true; } } } else { for (int i = 0; i < s; i++) { if (a[i] == null) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 只要删除成功都是累加 return true; } } } return false; }
@Override public Iterator<e> iterator() { return new ArrayListIterator(); }
private class ArrayListIterator implements Iterator<e> { ......
// 全局修改总数保存到当前类中 /** The expected modCount value */ private int expectedModCount = modCount;
@SuppressWarnings("unchecked") public E next() { ArrayList<e> ourList = ArrayList.this; int rem = remaining; // 如果创建时的值不相同,抛出异常 if (ourList.modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (rem == 0) { throw new NoSuchElementException(); } remaining = rem - 1; return (E) ourList.array[removalIndex = ourList.size - rem]; }
...... } } </e></e></e></e></e> |
List、Set、Map 都可以通过Iterator进行遍历,这里仅仅是通过List举例,在使用其他集合遍历时进行增删操作都需要留意是否会触发ConcurrentModificationException异常。
3. 解决方案
map.remove() 改:iterator.remove()
使用Iterator遍历集合时,不要改动被迭代的对象,可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护modCount和expectedModCount值的一致性。