编程规约-处理Map List Set
Map
Collectors 类的 toMap()方法 相同键相关联的值之间的冲突
在使用 java.util.stream.Collectors 类的 toMap()方法转为 Map 集合时,一定要使用含有参数类型为 BinaryOperator,参数名为 mergeFunction 的方法,否则当出现相同 key值时会抛出 IllegalStateException 异常。
toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
参数
keyMapper
- 产生密钥的映射函数
valueMapper
- 产生值的映射函数
mergeFunction
- 一个合并函数,用于解决与相同键相关联的值之间的冲突,提供给 Map.merge(Object, Object, BiFunction)
说明:参数 mergeFunction 的作用是当出现 key 重复时,自定义对 value 的处理策略。
正例:
List<Pair<String, Double>> pairArrayList = new ArrayList<>(3);
pairArrayList.add(new Pair<>("version", 12.10));
pairArrayList.add(new Pair<>("version", 12.19));
pairArrayList.add(new Pair<>("version", 6.28));
Map<String, Double> map = pairArrayList.stream().collect(
// 生成的 map 集合中只有一个键值对:{version=6.28}
Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v2));
反例:
String[] departments = new String[]{"iERP", "iERP", "EIBU"};
// 抛出 IllegalStateException 异常
Map<Integer, String> map = Arrays.stream(departments).collect(
Collectors.toMap(String::hashCode, str -> str));
Collectors 类的 toMap()方法 value 为 null 时会抛 空指针异常
在使用 java.util.stream.Collectors 类的 toMap()方法转为 Map 集合时,一定要注意当 value 为 null 时会抛 空指针异常。
说明:在 java.util.HashMap 的 merge 方法里会进行如下的判断:
if (value == null || remappingFunction == null) {
throw new NullPointerException();
}
反例:
List<Pair<String, Double>> pairArrayList = new ArrayList<>(2);
pairArrayList.add(new Pair<>("version1", 8.3));
pairArrayList.add(new Pair<>("version2", null));
Map<String, Double> map = pairArrayList.stream().collect(
// 抛出 NullPointerException 异常
Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v2));
使用 Map 的方法 keySet()/values()/entrySet()返回的集合对象
使用 Map 的方法 keySet()/values()/entrySet()返回集合对象时,不可以对其进行添加元素操作,否则会抛出 UnsupportedOperationException 异常。
使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。
说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key 所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.forEach 方法。
正例:values() 返回的是 V 值集合,是一个 list 集合对象;keySet()返回的是 K 值集合,是一个 Set 集合对象;entrySet()返回的是 K-V 值组合集合。
高度注意 Map 类集合 K/V 能不能存储 null 值的情况
线程安全【key 不允许为 null,Value 不允许为 null】:
-
Hashtable:key 不允许为 null,Value 不允许为 null,父类 Dictionary。
-
ConcurrentHashMap:key 不允许为 null,Value 不允许为 null,父类 AbstractMap,锁分段技术(JDK8:CAS)。
线程不安全【value 允许为 null】:
-
HashMap:key 允许为 null,value 允许为 null,父类 AbstractMap。
-
TreeMap:key 不允许为 null,value 允许为 null,父类 AbstractMap。
反例:由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,而事实上,存储 null 值时会抛出 NPE 异常。
List
ArrayList 的 subList 结果不可强转成 ArrayList
ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。
说明:subList()返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 本身,而是 ArrayList 的一个视图,对于 SubList 的所有操作最终会反映到原列表上。
在 subList 场景中,注意对父集合元素的增加或删除
在 subList 场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。
使用集合转数组的方法
使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为 0 的空数组。
反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误。
正例:
List<String> list = new ArrayList<>(2);
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);
说明:使用 toArray 带参方法,数组空间大小的 length:
-
等于 0,动态创建与 size 相同的数组,性能最好。
-
大于 0 但小于 size,重新创建大小等于 size 的数组,增加 GC 负担。
-
等于 size,在高并发情况下,数组创建完成之后,size 正在变大的情况下,负面影响与2 相同。
-
大于 size,空间浪费,且在 size 处插入 null 值,存在 NPE 隐患。
使用工具类 Arrays.asList()把数组转换成集合
使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。
说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配器模式,只是转换接口,后台的数据仍是数组。
String[] str = new String[]{ "chen", "yang", "hao" };
List list = Arrays.asList(str);
第一种情况:list.add("yangguanbao"); 运行时异常。
第二种情况:str[0] = "change"; list 也会随之修改。
Arrays.ArrayList 源码
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
Set
利用 Set 元素唯一的特性
利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的
contains()进行遍历去重或者判断包含操作。
标签:Map,Set,ArrayList,List,add,集合,new,null From: https://www.cnblogs.com/gcbeen/p/16723446.html