谈谈知识的融会贯通:以“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 中更灵活、更具可伸缩性的锁定机制 。
其他扩展文章
为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作
谈谈知识的融会贯通:以“java中的迭代器失效问题”为例的更多相关文章
- Java基础知识强化106:Java中 int 的各进制之间的转换
1.二.八.十.十六进制之间的转换 下面是示例代码,我们直接通过JDK工具库中的方法实现的,如下: public static Integer valueOf(String s, int radix ...
- Java基础知识强化101:Java 中的 String对象真的不可变吗 ?
1. 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...
- Java基础知识强化03:Java中的堆与栈
1.在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题. 一般,JV ...
- Java基础知识强化10:Java中的中间缓存变量机制
1.对于自增运算++j与j++,由于加一的执行顺序不同,所以Java中有中间缓存变量来储存其单个表达式的值,而j的自增自减的结果依然保留在原来的变量储存区.因为本体是j的值,而单个表达式的值是中间产生 ...
- Java基础知识强化19:Java中switch分支语句
java中switch语句: 这里expression控制表达式的数据类型只能是byte.short.char.int四种整型类型和枚举类型,不能是boolean类型: Java7(1.7)改进了sw ...
- Java基础知识强化24:Java中异常
1.什么是异常 ? Java程序运行中,常常会遇到非正常的现象,这种情况称为运行错误.根据性质可以分为错误和异常.Java程序中(无论谁写的代码),所有抛出(throw)的异常都必须从Th ...
- Java基础知识强化22:Java中数据类型转换
数据类型转换: (1). 自动转换 低级变量可以直接转换为高级变量,这叫自动类型转换.比如: byte b: int b: long b: float b: double b: 上面的语句可 ...
- Java基础知识强化21:Java中length、length()、size()区别
1.java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性.2.java中的length()方法是针对字符串String说的,如果想看这个 ...
- 第一篇 网站基础知识 第4章 Java中Socket的用法
第4章 Java中Socket的用法 4.1 普通Socket的用法 Java中的网络通信是通过Socket实现的,Socket分为ServetSocket和Socket两大类,ServetSocke ...
随机推荐
- JAVA核心技术第一卷第三章
JAVA中包含的数据类型:
- 我所理解Java集合框架的部分的使用(Collection和Map)
所谓集合,就是和数组类似——一组数据.java中提供了一些处理集合数据的类和接口,以供我们使用. 由于数组的长度固定,处理不定数量的数据比较麻烦,于是就有了集合. 以下是java集合框架(短虚线表示接 ...
- [转载]你所不了解的DevOps
DevOps开发运维训练营 一旦建立了创新的文化,即使那些并非科学家或者工程师的人——诗人.演员.记者——也能以团体的形式,接受科学文化的意义.他们信奉创新文化的概念.他们以促进这种文化的方式投票.他 ...
- angularjs等号运算
在angularjs的程序里,等号运算符有下面几种运算:
- 「ZJOI2017」树状数组(二维线段树)
「ZJOI2017」树状数组(二维线段树) 吉老师的题目真是难想... 代码中求的是 \(\sum_{i=l-1}^{r-1}a_i\),而实际求的是 \(\sum_{i=l}^{r}a_i\),所以 ...
- IM群聊消息的已读回执功能该怎么实现?
本文引用了架构师之路公众号作者沈剑的文章,内容有改动,感谢原作者. 1.前言 我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知 ...
- db2 报错 sqlcode=-420 自动类型转换的问题
今天在测试遇到一个问题,前台点击页面查询数据时报错: , SQLSTATE, SQLERRMC=DECFLOAT, DRIVER=4.18.60 根据sqlcode查询错误原因为:-420 22018 ...
- 基于.NET框架的消息通信组件ZMQ资料汇编-总目录
ZMQ是一个比较轻量级的消息通信组件,引用官方的说法: “ZMQ (以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程 ...
- [django]date类型和datetime类型过滤
搞清楚datetime.datetime和datetime.date模块 他们两个的格式区别 datetime模块 In [1]: from datetime import datetime In [ ...
- poj 1177 --- Picture(线段树+扫描线 求矩形并的周长)
题目链接 Description A number of rectangular posters, photographs and other pictures of the same shape a ...