首先说下不正确的打开方式:

第一:使用for循环删除集合的元素,示例代码如下

 ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (int i = 0; i < list.size(); i++) {
list.remove(i);
}
System.out.println(list);

结果输出为:

[b, d]

解说开始:

首先看下源码:

 public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}

解释:第一次进for循环,i=0 ,调用remove方法删除第一位的元素, 集合大小收缩,第一次删除完成后,list变成【b,c,d】;再次循环,i=1,调用remove方法删除了c 集合大小再次收缩,list变成【b,d】;再次循环,i=2,不符合条件,循环结束

第二:使用foreach循环删除元素,示例代码如下

 ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (String s : list) {
if (s.equals("b"))
list.remove(s);
}
System.out.println(list);

结果:这段代码居然抛出了异常 java.util.ConcurrentModificationException。

解说开始:

首先看下源代码:

 public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

解释:在Java中的foreach循环的工作原理就像一个iterator。

首次进入到foreach循环时,ArrayList创建一个内部迭代器类对象,以后循环就不再创建。每次循环的流程都是先调用迭代器对象的hasNext()方法,返回true,再调用next()方法,而每次调用next()方法时,首先会检测集合修改。
迭代器对象的实例字段就是检测的关键所在。实例字段在创建对象时赋值了一次,后面就没有再维护。
而调用remove(Object obj)方法时,集合本身跟踪改写操作(添加或者删除),ArrayLis类对象维护一个改写的变量,独立于迭代器对象维护的计数值。
内部迭代器类对象next()方法首先,判断集合的改写变量是否等于迭代器的改写值,不等于就抛出异常。
PS:
在测试中发现,若remove的是集合的倒数第二个元素或者最后一个元素,不会抛出异常。因为在remove以后,迭代器指向集合的末尾,再进入循环时,hasNext()方法返回false。循环结束。

so,接下来说下正确的打开方式——

方法一:用传统for循环,从集合最后元素向前循环删除元素,集合的size会变小,连带索引都会改变,但不会影响到前面的未循环元素。 示例代码如下
 ArrayList<Integer> a=new ArrayList<Integer>(15);
a.add(222);
a.add(3);
a.add(333);
a.add(000);
a.add(333);
a.add(4); for(int s=a.size()-1;s>=0;s--){
if(a.get(s).intValue()==333){
a.remove(s);
}
}
方法二:使用Iterator的remove()方法删除集合中的元素  示例代码如下
 privatevoid screenBlackNameList(List<SharedBoardSmsWrapper> source, List<BlackNameListModel> blackNameList){
Iterator<SharedBoardSmsWrapper> sourceIt=source.iterator();
while(sourceIt.hasNext()){
SharedBoardSmsWrapper tmpSharedBoardSmsWrapper=sourceIt.next();
Iterator<BlackNameListModel> blackNameListIt=blackNameList.iterator();
while(blackNameListIt.hasNext()){
BlackNameListModel tmpBlackNameListModel=blackNameListIt.next();
if(tmpSharedBoardSmsWrapper.getSource().equals(tmpBlackNameListModel.getSource())){
sourceIt.remove();
break;
}
}
}
}
 
 
 

Java循环删除集合多个元素的正确打开方式的更多相关文章

  1. (CSDN 迁移) JAVA循环删除List的某个元素

    若列表中只可能存在一个则可以用简单的循环删除,不多说. 若列表中可能存在多个,尤其是可能有多个连续的需要删除,用简单循环有可能发生异常. 需要使用迭代器(Iterator),两种具体实现: 逻辑上是一 ...

  2. for循环删除集合陷阱

    首先看下面的代码: import java.util.LinkedList;import java.util.List; public class DeleteCollection {         ...

  3. 集合赋值及for循环删除符合条件的元素

    一.Java语言中ArrayList对象能直接赋值给另一个ArrayList对象吗? https://zhidao.baidu.com/question/399214655.html ArrayLis ...

  4. ArrayList之foreach循环删除倒数第二个元素,不触发fail-fast机制

    今天一朋友问了个问题,对于如下一段代码,运行后会有怎样的结果? public class ArrayListTest { public static void main(String[] args) ...

  5. Python笔记:用for循环删除列表中的元素

    for运行过程中会有一个指针来记录当前循环的元素是哪一个,一开始这个指针指向第0个元素,然后获取它,接着删除第0个元素,这时候,原来是第1个的元素会变成第0个,当指针向后移动一次,指向了现在第1个元素 ...

  6. python循环删除list中的元素

    直接上例子: a = [1,2,3,4,5,6] for i in a: a.remove(i) print(a) 返回:[2, 4, 6] 循环a,想删除a的所有元素,但实际确有数据保留了下来,这是 ...

  7. Java思考——HashSet集合如何保证元素的唯一性也就是不包含重复元素?

    首先将源码逐级找出来1.HashSet<String> hs=new HashSet<String>();         hs.add("hello"); ...

  8. C#实现在foreach中删除集合中的元素

    List<string> str = new List<string>(); str.Add( "zs"); str.Add("ls") ...

  9. java的取出map里所有元素的两种方式

    /* * 取出map元素的两种方式 */package com.map.test; import java.util.HashMap;import java.util.Iterator;import ...

随机推荐

  1. 每天一点Android干货-时间与日期、进度条

    时间控件TimePicker的使用方法 timePicker.setIs24HourView(true); //设置是否以24小时制显示 timePicker.getCurrentHour(); // ...

  2. Sublime Text 3使用指南(1)——安装package control组件

    按Ctrl+`, 调出console 控制台中粘贴一下代码: import urllib.request,os; pf = 'Package Control.sublime-package'; ipp ...

  3. C++多线程の线程通信future,promise,async

  4. Java读取Level-1行情dbf文件极致优化(2)

    最近架构一个项目,实现行情的接入和分发,需要达到极致的低时延特性,这对于证券系统是非常重要的.接入的行情源是可以配置,既可以是Level-1,也可以是Level-2或其他第三方的源.虽然Level-1 ...

  5. [OC] Podfile 格式内容

    platform :ios, '8.0' target :'targetName' do pod 'Masonry', '~> 1.0.1' pod 'SDCycleScrollView', ' ...

  6. Spark学习(四) -- Spark作业提交

    标签(空格分隔): Spark 作业提交 先回顾一下WordCount的过程: sc.textFile("README.rd").flatMap(line => line.s ...

  7. js 单例模式笔记

    单例指一个类只有一个实例,这个类自行创建这个实例. 利用对象字面量直接生成一个单例: var singleton = { prop: 1, method: function(){ console.lo ...

  8. 微信小程序-视图模板

    定义模板 使用name属性,作为模板的名字.然后在<template/>内定义代码片段,如: <!-- index: int msg: string time: string --& ...

  9. 封装的ajax请求

    在做登录注册这类提交表单数据时,我们经常需要局部刷新网页来验证用户输入的信息,这就需要用到ajax请求,我们通常需要获取表单中的数据,发起ajax请求,通过服务程序,与数据库的数据进行比对,判断信息的 ...

  10. 通过nginx代理之后,获取客户端ip

    1.相关nginx配置(通过header将客户端ip,host等信息传入) location ~ .*.do$ { proxy_set_header X-Real-IP $remote_addr; p ...