android list集合遍历,Java list集合遍历操作遇到的问题

Java程序员在使用java list集合遍历操作时经常会遇到一些问题,遇到问题该如何解决,想必一些新手也是非常极手,在此,小编给大家汇总了一些java list集合遍历操作常见的问题,给大家做详细分析。

8415714ef3460526026a1f4d9e3f7243.png

Java list集合遍历操作常见的问题

1、下面四个方法有什么问题吗?为什么?

public void remove1(ArrayList list) {

for(Integer a : list){

if(a <= 10) {

list.remove(a);

}

}

}

public void remove2(ArrayList list) {

Iterator it = list.iterator();

while(it.hasNext()) {

if(it.next() <= 10) {

it.remove();

}

}

}

public void remove3(ArrayList list) {

Iterator it = list.iterator();

while(it.hasNext()) {

it.remove();

}

}

public void remove4(ArrayList list) {

Iterator it = list.iterator();

while(it.hasNext()) {

it.next();

it.remove();

it.remove();

}

}

答:这个问题很小儿科,答案如下。

remove1 方法会抛出 ConcurrentModificationException 异常,这是迭代器的一个陷阱,foreach 遍历编译后实质会替换为迭代器实现(普通for循环不会抛这个异常,因为list.size方法一般不会变,所以只会漏删除),因为迭代器内部会维护一些索引位置数据,要求在迭代过程中容器不能发生结构性变化(添加、插入、删除,修改数据不算),否则这些索引位置数据就失效了,避免的方式就是使用迭代器的 remove 方法。

remove2 方法可以正常运行,无任何错误。

remove3 方法会抛出 IllegalStateException 异常,因为使用迭代器的 remove 方法前必须先调用 next 方法,next 方法会检测容器是否发生了结构性变化,然后更新 cursor 和 lastRet 值,直接不调用 next 而 remove 会导致相关值不正确。

remove4 方法会抛出 IllegalStateException 异常,理由同 remove3,remove 调用一次后 lastRet 值会重置为 -1,没有调用 next 去设置 lastRet 的情况下再直接调一次 remove 自然就状态异常了。

2、下面程序片段的 remove 方法想删除 list 列表中的所有 "android",请分别说说其各个 remove 方法有没有问题?为什么?该怎么解决?

ArrayList list = new ArrayList();

list.add("java");

list.add("android");

list.add("android");

list.add("c");

list.add("c++");

list.add("c");

public void remove1(ArrayList list) {

for (inti=0; i

String s = list.get(i);

if (s.equals("android")) {

list.remove(s);

}

}

}

public void remove2(ArrayList list) {

for (Strings: list) {

if (s.equals("android")) {

list.remove(s);

}

}

}

答:上面程序的 remove1 方法和 remove2 方法运行情况如下。

remove1 方法执行后第二个 “android” 字符串没有被删掉,因为我们可以看下 ArrayList 的 remove 方法(ArrayList 有两个同名不同参的 remove 方法)实现核心代码:

public boolean remove(Object o) {

if (o == null) {

......

} else {

//一般元素走这个分支

for (int index = 0; index < size; index++)

if (o.equals(elementData[index])) {

fastRemove(index);

return true;

}

}

return false;

}

private void fastRemove(int index) {

modCount++;

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

}

可以看到最终删除会执行 System.arraycopy 方法而导致删除元素时涉及到数组元素的移动,所以在遍历第一个字符串 "android" 时因为符合删除条件,所以将该元素从数组中删除,并且将后一个元素移动(也就是第二个字符串 "android")至当前位置,导致下一次循环遍历时后一个字符串 "android" 并没有被遍历到,所以无法删除,同时由于每删除一次 size 也减一,所以其实每次都会向前移位,也会导致越来越多的元素无法被遍历获取。解决的办法就是倒序遍历删除(千万不要认为将 for 循环里 list.size() 提到外边先变量取值就可以删除,这样会报列表索引越界),这种方法的效率相对好些,如下:

public void remove1(ArrayList list) {

for(int i=list.size()-1; i>=0; i--) {

String s = list.get(i);

if (s.equals("android")) {

list.remove(s);

}

}

}

因为数组倒序遍历时即使发生元素删除也不影响后序元素的遍历。

remove2 方法运行会报 for-each 著名的并发修改异常 java.util.ConcurrentModificationException,因为迭代器内部会维护一些索引位置数据,要求在迭代过程中容器不能发生结构性变化(添加、插入、删除,修改数据不算),否则这些索引位置数据就失效了,修改的方式就是使用迭代器的 remove 方法替换 remove2 中的实现即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值