Java基础361问第4问——List如何遍历删除指定元素

这道题是面百度时的一个问题,也是一道很经典的题目

给定一个整数集合{1,2,2,3,4},删除其中能够被2整除的元素(即最后集合变为{1,3})

看到这个问题,我开始觉得很简单

for (int i = 0; i<list.size(); i++) {
            if(list.get(i)%2==0){
                list.remove(i);
            }
        }

但是结果不是{1,3}而是{1,2,3},为什么会发生这么奇怪的结果呢?一切都要从这个remove方法说起

public E remove(int index) {
        Objects.checkIndex(index, size);
        final Object[] es = elementData;

        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        fastRemove(es, index);

        return oldValue;
    }
private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
        if ((newSize = size - 1) > i)
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }
/**
     * Copies an array from the specified source array, beginning at the
     * specified position, to the specified position of the destination array.
     * @HotSpotIntrinsicCandidate
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

当我们遍历到下标为1的第二个元素2时,做了如下操作

> 下标                      0   1  2  3   4
> 原集合                    1   2  2  3   4
> 新集合                    1   2  3  4

也就是说集合在执行remove之后顺序已经发生了改变,当我们继续遍历下标为2的元素时,本来为2的元素现在被改变到下标为1的位置,这就造成了2这个元素被完美错过了!所以得出的结果是{1,2,3}而不是{1,3}

如果我们在IDE编写上述代码时,编译器会用黄色背景色提醒我们:
在这里插入图片描述

Suspicious ‘List.remove()’ in the loop less… (Ctrl+F1)
Inspection info: Reports when list.remove(index) is called inside the ascending counted loop. This is suspicious as list becomes shorter after that and the element next to removed will not be processed. Simple fix is to decrease the index variable after removal, but probably removing via iterator or using removeIf method (since Java 8) is a more robust alternative. If you don’t expect that remove will be called more than once in a loop, consider adding a break command after it.

编译器发出了一个良性的提示——小伙子你的循环删除元素有可能会遇到问题,你小心一点

说了会出现的问题和原因,最后我们说一下解决方案

逆序遍历元素

举个例子{2,3,2,4,5}


> 下标                      4   3  2    1     0
> 原集合                    2   3  2    4     5
> 新集合                         3  2    4    5
> 新集合                            3   4     5 

遍历到某个元素发现需要删除,那么直接删除这个元素

1 如果这个元素是第一个元素,那么直接删除,其他元素顺序不用更改,不影响接下来的遍历
2 如果不是第一个元素,那么这个元素之前的元素需要改变位置,由于之前的元素已经判断过所以即使改变了位置也没问题,这个元素之后的元素不会改变位置,所以仍然不影响后续的遍历

逆序遍历解决问题

for (int i = list.size()-1; i >=0; i--) {
            if(list.get(i)%2==0){
                list.remove(i);
            }
        }
  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值