【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;
}
- 点赞
- 收藏
- 关注作者
评论(0)