【Java深入浅出】集合篇
【摘要】 本文深入浅出地介绍了Java中的集合相关类型的方方面面。用问答、代码的形式针对易混淆、易搞错的场景进行了针对性阐示。
Java中关键的List、Set有哪些?它们的集成关系是什么样的?
关键List:ArrayList、LinkedList、Vector。
关键Set:HashSet、LinkedHashSet、TreeSet。
整理的整整齐齐的集成关系图如下:
这么多List、Set,他们之间肯定有很多相似跟区别,都有哪些关键的关注点呢?
它们的一些关键特点、要素汇总表如下:
Arrays.asList创建出来的List与一般new出来的ArrayList有什么区别?
解析:Arrays.asList函数生成的List的长度不可变,内容可变。
上述代码第三行是修改了用来创建List的原始数据中的元素,arrayList里的内容也跟着改变了。
上述代码第五行会报错,因为经过Arrays.asList()处理后返回了一个固定长度结构的列表,无法调用add、remove、clear等方法。
在使用foreach方式遍历ArrayList的场景中,通过ArrayList.remove()方法删除其中的元素会报错吗?
首先,上面代码这样写是不合适的。虽然不会报错。不会报错的原因是因为B是倒数第二个元素。在foreach遍历的循环中调用集合的remove方法,当且仅当删除的是倒数第二个元素的时候才不会报错。删除其它元素(如删除A或者C)都会报错(ConcurrentModificationException异常)。
原理解析:
这是因为,foreach内部是使用了List的的迭代器实现的,遍历下一个元素时会先调用hashNext(),为true后再调用next()方法实现的。next方法中会先判断该List当前的修改计数器的值(modCount)是否没变,如果变了就报错。
而当通过remove删除倒数第二个元素遍历到下一个元素的逻辑时,调用hasNext()返回false,方法误判cursor的指向已经超过数组范围(因为刚才删除导致了size减一,使cursor与size正好相等)导致遍历提前结束,实际上最后一个元素“C”没有遍历到就结束循环了。
如果代码修改为删除的是“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)