一、Map类型的案例、源码解析与规约
首先,来看下面一段代码;思考下这个方法会有什么问题?
有些查询结果会报java.lang.IllegalStateException,这是为什么呢?根据报错,定位并剖析Collectors.toMap方法内部构造:
这里引出一个集合规约:
【强制】在使用java.util.stream.Collectors类的toMap()方法转为Map集合时,一定要使用含有参数类型为BinaryOperator,参数名为mergeFunction的方法,否则当出现相同key值时会抛出IllegalStateException异常
按照规约,加上参数类型为BinaryOperator,参数名为mergeFunction的方法,如下图所示:
然而,再次测试运行,会抛出空指针异常。因此,需要再次从源码入手,一行一行地追根究底:
显然根据堆栈信息,NPE是藏在HashMap地merge方法中地,点进去继续看:
一行一行地找,先看map的merge方法:
二、List类型的源码解析与规约
首先,给出一个结论:ArrayList的subList结果不可强转成ArrayList;然后看如下源码:
注释的第一句话就解释清楚了,内部类SubList,并不是ArrayList本身,而是ArrayList的一个视图;对于SubList的所有操作最终会反映到原列表上。
SubList的所有操作最终会反映到原列表上,因此ArrayList的subList()返回的是ArrayList的内部类SubList,强转成ArrayList,则会抛出ClassCastException异常。
在subList场景中,需要注意:
- 高度注意对父集合元素的增加或删除,均会导致子列表的遍历;
- 增加、删除产生ConcurrentModificationException;
- 每次sublist子列表的遍历、增加、删除都会调用checkForComodification()。
扩展
集合Collection与Set、List、Map、Queue的关系图
上图中红色为接口;蓝色为抽象类;绿色为并发包中的类;灰色为早期线程安全的类