java 迭代器失效_谈谈知识的融会贯通:以“java中的迭代器失效问题”为例

提示

文中涉及知识点:

Collection 、 Iterator

Guava 中的 Lists.partition 方法

如果你对这两个知识点不了解,强烈建议阅读文中引用的参考文章。

场景一:以ArrayList为例

参考文章 java迭代器失效 和 Collection与Iterator的remove()方法区别与ConcurrentModificationException异常 ,可将迭代器和 Collection 的不同理解为:迭代器是基于 Collection 的一个视图,迭代器执行诸如 remove 和 add 之类的操作时,会首先在底层 Collection 上操作,最后将 expectedModCount 更新为新的 modCount ,而直接操作 Collection 则只会更新 modCount ,导致 fail-fast 机制生效。因此我们应在涉及到此类操作时尽可能只使用迭代器,可参考文章 Java:使用Iterator迭代器遍历集合数据 。

场景二:以Guava中的Lists.partition为例

参考文章 列表分片实现 和 Java 集合细节(三):subList 的缺陷 ,可知 Lists.partition 的底层实现就是 subList 方法,而 subList 函数返回仅仅只是一个视图,因此这里的 subList 其实和前面所述的迭代器在概念上是一样的(只是新的分片 List 的计数变量不叫 expectedModCount,而是和原 List 一样的 modCount,通过 this 区分),它们都是在原 List 的上层产生的视图,然后我们使用这个视图进行各种操作。因此,第二篇文章中所谓的 subList 缺陷其实不能叫做缺陷:我们在原 List 上通过 subList 获得其分片视图后,就不应该再操作原 List 了(类似于迭代器,我们获得一个 List 的迭代器后,应使用该迭代器进行各种操作,如前所述,此时针对原 List 的一些操作是危险的)。

当然,第二篇文章之所以将其称为“缺陷”也有原因:我们通常会认为获得的新分片 List 是新的 List ,这就是语言层面的理解了。

场景三:浅谈Guava中的集合类

其实,Guava中的多种集合如Maps、Lists均没有实现自定义的add操作。以Lists为例,当我们用Lists.transform或是Lists.partition函数返回新的集合时,都是Lists的内部类,这些内部类同样没有实现add方法,因此当我们视图在新的集合上进行add操作时,就会调用AbstractList的add方法,此方法会直接抛出UnsupportedOperationException。不过,我们仍旧可以在旧的集合中进行add操作,此时新集合也能看到刚刚add进去的元素,这是需要注意的。

总结

有时很多概念描述有很大不同,其实内部原理是相通甚至相同的,将这些概念融会贯通将大有裨益。

如果你了解 C++ 的话,可以参考 vector 容器的 insert 和 erase 方法,其实底层原理和 java 也是类似的。

扩展:多线程场景

注意,ArrayList并不是线程安全的,若不追求数据强一致性,可使用 CopyOnWriteArrayList 方法,可参考 聊聊并发-Java中的Copy-On-Write容器 和 JDK 5.0 中更灵活、更具可伸缩性的锁定机制 。

其他扩展文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值