【Java深入浅出】集合篇

举报
MDKing 发表于 2023/12/26 15:05:43 2023/12/26
【摘要】 本文深入浅出地介绍了Java中的集合相关类型的方方面面。用问答、代码的形式针对易混淆、易搞错的场景进行了针对性阐示。

Java中关键的List、Set有哪些?它们的集成关系是什么样的?


关键List:ArrayList、LinkedList、Vector。
关键Set:HashSet、LinkedHashSet、TreeSet。

整理的整整齐齐的集成关系图如下:

1.png

这么多List、Set,他们之间肯定有很多相似跟区别,都有哪些关键的关注点呢?


它们的一些关键特点、要素汇总表如下:

2.png

3.png

Arrays.asList创建出来的List与一般new出来的ArrayList有什么区别?


4.png

解析:Arrays.asList函数生成的List的长度不可变,内容可变。

上述代码第三行是修改了用来创建List的原始数据中的元素,arrayList里的内容也跟着改变了。

上述代码第五行会报错,因为经过Arrays.asList()处理后返回了一个固定长度结构的列表,无法调用add、remove、clear等方法。

在使用foreach方式遍历ArrayList的场景中,通过ArrayList.remove()方法删除其中的元素会报错吗?


5.png

首先,上面代码这样写是不合适的。虽然不会报错。不会报错的原因是因为B是倒数第二个元素。在foreach遍历的循环中调用集合的remove方法,当且仅当删除的是倒数第二个元素的时候才不会报错。删除其它元素(如删除A或者C)都会报错(ConcurrentModificationException异常)

原理解析:

是因为,foreach内部是使用了List的的迭代器实现的,遍历下一个元素时会先调用hashNext(),为true后再调用next()方法实现的。next方法中会先判断该List当前的修改计数器的值(modCount)是否没变,如果变了就报错。
而当通过remove删除倒数第二个元素遍历到下一个元素的逻辑时,调用hasNext()返回false,方法误判cursor的指向已经超过数组范围(因为刚才删除导致了size减一,使cursor与size正好相等)导致遍历提前结束,实际上最后一个元素“C”没有遍历到就结束循环了。

6.png

如果代码修改为删除的是“C”,在删除完后遍历下一个元素触发执行hasNext()时,cursor为3,size为2,返回true,误认为还有下一个,所以依旧执行到next()中抛出ConcurrentModificationException异常。

附加延伸:如果上面的ArrayList换成LinkedLis的话,删除倒数第二、倒数第一个元素都不会报错。因为LinkedList.hasNext方法略有不同(如下),由此看出用当前索引不等于size这种方式判断是否退出遍历比较脆弱,当前索引小于或等于size的方式更健壮些。

public boolean hasNext() {
    return nextIndex < size;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。