博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java ArrayList 踩坑记录
阅读量:5775 次
发布时间:2019-06-18

本文共 6290 字,大约阅读时间需要 20 分钟。

  做编程的一个常识:不要在循环过程中删除元素本身(至少是我个人的原则)。否则将发生不可预料的问题。

  而最近,看到一个以前的同学写的一段代码就是在循环过程中删除元素,我很是纳闷啊。然后后来决定给他改掉。然后引发了另外的惨案。

  原来的代码是这样的:

  看了如上代码,我很是郁闷,然后给改成如下:

  这下出事了,原本只有一个元素的result,现在变成了两个了,这是为什么呢?妈蛋,我明明已经remove掉了啊。

  也想过百度一下,但是木有搞定啊。然后,拿出看家绝招,断点调试,进入list.remove(Integer) 方法。其源码如下:

/**     * Removes the first occurrence of the specified element from this list,     * if it is present.  If the list does not contain the element, it is     * unchanged.  More formally, removes the element with the lowest index     * i such that     * (o==null ? get(i)==null : o.equals(get(i)))     * (if such an element exists).  Returns true if this list     * contained the specified element (or equivalently, if this list     * changed as a result of the call).     *     * @param o element to be removed from this list, if present     * @return true if this list contained the specified element     */    public boolean remove(Object o) {        if (o == null) {            for (int index = 0; index < size; index++)                if (elementData[index] == null) {                    fastRemove(index);                    return true;                }        } else {            for (int index = 0; index < size; index++)                if (o.equals(elementData[index])) {                    fastRemove(index);                    return true;                }        }        return false;    }

  原来,由于我使用Integer作为删除元素的条件,这里把Integer当作一个元素去比较了,而并不是平时我们以为的自动拆装箱变为int了。 而进入这个方法的意思,是要找到和元素内容相等的元素,然后删除它。而我给的是一个索引,自然就不相等了,没有删除也是自然了,因为就会看到重复的元素出来了。

  我们再来看一下根据索引删除元素的源码,对比一下:

/**     * Removes the element at the specified position in this list.     * Shifts any subsequent elements to the left (subtracts one from their     * indices).     *     * @param index the index of the element to be removed     * @return the element that was removed from the list     * @throws IndexOutOfBoundsException {
@inheritDoc} */ 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; }

  从这里我们可以看到,根据索引删除ArrayList元素的原理是,将原来的数组排除要删除的索引,然后复制到新的数组去,然后将最后一个元素置为null,留给GC回收。并把删除的元素返回。

  这样,一下就明白了删除ArrayList元素到底是咋么一回事了。修复方案就简单了,将Integer替换为int即可:

// Integer lastAIndex = 0;   //替换成int        int lastAIndex = 0;

  当然了,最后,我还是换成了另一个更稳妥的方案了,用另一个容器接收最终的结果

  虽然自动拆装箱很方便,也很实用,但是有时一不小心就会把自己给埋坑里了,当心了。尤其是针对线上问题。

  毕竟,代码中的一点点小问题,一到线上就会被无限放大,不可掉以轻心啊!

 

转载地址:http://zkeux.baihongyu.com/

你可能感兴趣的文章
Redis笔记3:Jedis连接自动释放
查看>>
cell侧滑显示多个按钮(Swift)
查看>>
simpleDateFormat线程不安全
查看>>
php一个命名空间的坑
查看>>
Mysql出现大量TIME_WAIT状态端口占用的解决方法 windows/linux/centos
查看>>
微信企业号登录授权Java实现获取员工userid根据userid换openid
查看>>
static_cast, dynamic_cast, const_cast探讨
查看>>
sql筛选出每一人的时间最新的一条记录
查看>>
sql ,hql 使用 or 注意使用()
查看>>
今天发现一个 动态dns工具
查看>>
网上找的TCP连接示意图...
查看>>
Bootstrap3学习笔记:辅助样式
查看>>
Windows Phone 7 控件重写之TextBox 圆角输入框
查看>>
微信消息中的CreateTime转换成标准格式的时间
查看>>
Fastjson的SerializerFeature序列化属性
查看>>
前后端分离的思考 - 网站URL设计
查看>>
IOS学习
查看>>
Quartz,spring动态加载定时任务
查看>>
日期类相关转换
查看>>
Android JNI 开发系列(三)Android Studio中C与Cpp文件构建脚本
查看>>