当前位置 : IT培训网 > Java开发 > Java培训 > Java list集合遍历操作遇到的问题

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

时间:2018-03-01 14:31:51  来源:Java培训网  作者:IT培训网  已有:名学员访问该课程
Java程序员在使用java list集合遍历操作时经常会遇到一些问题,遇到问题该如何解决,想必一些新手也是非常极手,在此,小编给大家汇总了一些java list集合遍历操作常见的问题,给大家做详细分析。

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

Java list集合遍历操作遇到的问题_www.itpxw.cn

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

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

public void remove1(ArrayList<Integer> list) {

    for(Integer a : list){

        if(a <= 10) {

            list.remove(a);

        }

    }

}

public void remove2(ArrayList<Integer> list) {

Iterator<Integer> it = list.iterator();

    while(it.hasNext()) {

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

            it.remove();

        }

    }

}

public void remove3(ArrayList<Integer> list) {

    Iterator<Integer> it = list.iterator();

    while(it.hasNext()) {

        it.remove();

    }

}

public void remove4(ArrayList<Integer> list) {

    Iterator<Integer> 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<String> list = new ArrayList<String>();

list.add("java");

list.add("android");

list.add("android");

list.add("c");

list.add("c++");

list.add("c");

public void remove1(ArrayList<String> list) {

    for (inti=0; i<list.size(); i++) {

        String s = list.get(i);

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

            list.remove(s);

        }

    }

}

public void remove2(ArrayList<String> 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<String> 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)
0%

IT培训0元试听 每期开班座位有限.0元试听抢座开始! IT培训0元试听

  • 姓名 : *
  • 电话 : *
  • QQ : *
  • 留言 :
  • 验证码 : 看不清?点击更换请输入正确的验证码

在线咨询在线咨询

温馨提示 : 请保持手机畅通,咨询老师为您
提供专属一对一报名服务。

------分隔线----------------------------
------分隔线----------------------------

推荐内容

相关热点