HIT-2022春-软件构造IV 删除容器内元素时隐藏的陷阱

问题引入:

        在Java语言中,我们可以通过以下的语法结构进行对容器内元素的遍历(以字符串为例):

for(String word : Words) {
    
    implement ···
}

        这个操作是之前的C语言中没有定义的操作,其内部实现原理是通过一个Iterator,即迭代器进行实现的,具体实现如下: 

Iterator iter = Words.iterator();
while (iter.hasNext()) {
    String word = iter.next();
    implement ···;
}

        使用迭代器后,类似于链表的原理,迭代器不断执行操作,直到没有下一个元素为止。

但是当遇到遍历元素进行删除时,例如下一段代码(来自于讲义第四章的例子)

public static void dropCourse6(ArrayList<String> subjects) {
    MyIterator iter = new MyIterator(subjects);//自定义的迭代器功能
    while (iter.hasNext()) {
        String subject = iter.next();
        if ( subject.startWith("6.")) {
            subjects.remove(subject);//如果课程以"6."开头,则删除
        }
    }
}

        当执行测试用例时,发现与预期结果不符? 

dropCourse6(["6.045","6.005","6.813"])
//expected [], actual ["6.005"]

问题分析: 

        按照函数的功能,三门课程都应该被删除,而有一门却没有被删除。要想解决这个问题,就要深入迭代器的实现原理以及分析方法流程。

        分析函数流程,在刚开始的时候,迭代器指向的下标是0,也就是这个容器内的第一个元素。识别到第一个字符串时,发现是以"6."开头的,容器执行删除操作。迭代器的list加1,但是此时容器的第一个元素被删除,原来的第2,3个元素递补到了第1,2个元素,但是此时迭代器指向的是第2个元素,也就是原本的第3个元素,所以第2个元素被略过去了,导致没有被删除,而是被留在了集合中。

        推广到更多的元素,如果仍旧使用这种在容器内的方法删除,就会导致有越来越多的元素被略过去,从而产生非常严重的错误。

解决方法:

        不应该在容器内删除元素,而是应该利用容器内的元素的mutable特性,利用迭代器,指向要删除的元素进行删除,避免了因为下标改变造成的影响。具体代码如下:

Iterator iter = subjects.iterator();
while (iter.hasNext()) {
    String subject = iter.next();
    if (subject.startWith("6.")) {
        iter.remove();
    }
}

问题总结: 

        迭代器的实现主要是利用了List,Map,Set这种容器类接口的mutable特性,从而让迭代器和容器内的元素指向同一空间进行操作得以实现。

得到的启示:

        执行删除操作时出现了小问题,看似正确的代码在执行时也会出现出乎意料的结果,所以就要求我们要修炼内功,练就一双火眼金睛,能够发现隐藏的小漏洞。道阻且长,仍需努力!

——2022.06.09  By Cosmic-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值