报错示例一:
List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); for(String str : list){ if(!str.equals("1")) { list.remove(str); } } System.out.println(list.size());
错误使用二:这种情况不会报错,因为最后一个元素未被遍历到就程序跳出了循环遍历
List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); for(String str : list){ if(!str.equals("1")) { list.remove(str); } } System.out.println(list.size());
方法一:for循环遍历
List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); for (int i = 0; i < list.size(); i++) { String item = list.get(i); if("2".equals(item)) { //逻辑判断,剔除满足条件的元素 list.remove(item); //元素删除后,后面的元素位置向前挪一位,位置索引i需要自减一,否则访问不到后面的元素 i--; } } System.out.println(list.size());
方法二:使用集合的迭代器
List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); for(Iterator<String> it = list.iterator(); it.hasNext(); ){ if("2".equals(it.next())) { //使用迭代器的删除方法,不要使用集合对象的删除方法remove it.remove(); } } System.out.println(list.size());
原因说明:
1、如果使用增强for循环进行遍历,那么实际上使用的是集合的迭代器进行遍历,这时如果使用的是集合对象自己的删除方法,迭代器不知道元素集合发生了变化,进行获取下一个元素的时候就会爆出错误:ConcurrentModificationException,但这里有一点需要注意,如果遍历过程中第一个被删除的元素处在倒数第二个被遍历的位置时,程序不会报错,正常结束。实际的结果是:集合中最后一个元素之前,会调用迭代器的hasNext()方法,该方法发现当前位置索引等于集合元素数量,判断遍历结束,跳出循环,实则最后一个元素未被遍历到。
2、第一种遍历删除方法,是自己控制并调整元素位置索引,只要位置索引控制正确,就可以正常删除元素,否则会出现IndexOutOfBoundsException
3、第二种遍历删除直接使用迭代器进行遍历,而且删除时使用的迭代器的删除元素方法,这个删除方法里面会对位置索引进行调整,使得迭代器在继续遍历查找下一个元素时,不会抛出异常错误。