Java开发手册解析_编程规约-集合处理
创始人
2024-01-15 17:05:10
0

前言

《Java开发手册(黄山版)》编程规约-集合处理
该章节的知识点基本都来源于jdk源码,将结合源码及例子进行理解
备注:文章中的详细说明为手册本身内容
博客地址:芒果橙的个人博客 【http://mangocheng.com】

1.【强制】关于 hashCode 和 equals 的处理

  • 只要覆写 equals,就必须覆写 hashCode。
  • 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须覆写这两种方法。
  • 如果自定义对象作为 Map 的键,那么必须覆写 hashCode 和 equals。 说明:String 因为覆写了 hashCode 和 equals 方法,所以可以愉快地将 String 对象作为 key 来使用。

详细请参考

hashCode返回的是对象在哈希表(散列表)中的索引/位置
equals是用来比较两个对象是否相等
两个对象相等,及equals相等,且hashCode一定相等;但是hashCode相等,两个对象不一定相等

  • hashCode:保证性能
  • equals:保证可靠性

2.【强制】判断所有集合内部的元素是否为空,使用 isEmpty() 方法,而不是 size() == 0 的方式。

说明:在某些集合中,前者的时间复杂度为 O(1),而且可读性更好。

在一些集合中isEmpty和size方法的时间复杂度是一样的O(1),但也有一些集合中这个两个方法的时间复杂度不一致,最差可能为O(n)

// HashMap.java 
// 两个方法时间复杂度都是O(1)
public int size(){return size;}public boolean isEmpty(){return size==0;}
// ConcurrentLinkedQueue.java
// size进行了循环遍历,时间复杂度为O(n)
public int size(){int count=0;for(Node p=first();p!=null;p=succ(p))if(p.item!=null)// Collection.size() spec says to max outif(++count==Integer.MAX_VALUE)break;return count;}public boolean isEmpty(){return first()==null;}

3.【强制】在使用Collectors. toMap() 方法时,要传入第3个参数

详细:在使用 java.util.stream.Collectors 类的 toMap() 方法转为 Map 集合时,一定要使用参数类型为 BinaryOperator
说明:在使用 java.util.stream.Collectors 类的 toMap() 方法转为 Map 集合时,一定要使用参数类型为 BinaryOperator,参数名为 mergeFunction 的方法,否则当出现相同 key时会抛出IllegalStateException 异常。

Collectors.toMap()方法最少需要2个参数,会默认补充的第3个参数throwingMerger(),这个参数会指定当转化的数据有同key时的策略,存在相同key会抛出异常

// 示例
@Test
public void streamToMapTest() {// 初始化List people = new ArrayList<>(3);people.add(new Person("A", 23));people.add(new Person("A", 24));people.add(new Person("A", 25));people.add(new Person("B", 26));// 转化1:没有同key策略,抛异常Map map = people.stream().collect(Collectors.toMap(Person::getName, Person::getAge));// 转化2:设置以最后的值为准Map map2 = people.stream().collect(Collectors.toMap(Person::getName, Person::getAge, (v1, v2) -> v2));System.out.println(map2);}@Data
@AllArgsConstructor
class Person {private String name;private int age;
}
// Collectors.java
// toMap方法
public staticCollector>toMap(FunctionkeyMapper,FunctionvalueMapper){return toMap(keyMapper,valueMapper,throwingMerger(),HashMap::new);}
// throwingMerger方法
private static BinaryOperator throwingMerger(){return(u,v)->{throw new IllegalStateException(String.format("Duplicate key %s",u));};}

4.【强制】在使用 Collectors. toMap方法时,value值要非空

详细:在使用 java.util.stream.Collectors 类的 toMap() 方法转为 Map 集合时,一定要注意当 value为 null 时会抛 NPE 异常。

在合并转化时,会对传入的value进行非空判断

// Collectors.java
// toMap方法
public static>Collector toMap(FunctionkeyMapper,FunctionvalueMapper,BinaryOperator mergeFunction,Supplier mapSupplier){BiConsumer accumulator=(map,element)->map.merge(keyMapper.apply(element),valueMapper.apply(element),mergeFunction);return new CollectorImpl<>(mapSupplier,accumulator,mapMerger(mergeFunction),CH_ID);}// merge方法:对value进行判空Objects.requireNonNull(value);
default V merge(K key,V value,BiFunctionremappingFunction){Objects.requireNonNull(remappingFunction);  // 非空Objects.requireNonNull(value);              // 非空V oldValue=get(key);V newValue=(oldValue==null)?value:remappingFunction.apply(oldValue,value);if(newValue==null){remove(key);}else{put(key,newValue);}return newValue;}

5.【强制】ArrayList 的 subList 结果不可强转成 ArrayList

详细:ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常:java.util.RandomAccessSubList cannot be cast to
java.util.ArrayList。 说明:subList() 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 本身,而是 ArrayList 的一个视图,对于 SubList
的所有操作最终会反映到原列表上。

subList只是映射了从起始索引到目标索引的源list
修改subList,同时会作用于原ArrayList
注意使用subList的add方法时,最终元素存储的位置

@Testpublic void subListTest() {List list = new ArrayList<>(3);list.add("A");list.add("B");list.add("C");System.out.println("list:" + list);   // list:[A, B, C]List subList = list.subList(0, 2);System.out.println("sublist:" + subList);  // sublist:[A, B]  // 给subList添加数据:注意添加后的元素顺序System.out.println("=====对sublist操作=====");subList.add("D");System.out.println("sublist2:" + subList);      // sublist2:[A, B, D]System.out.println("list2:" + list);    // list2:[A, B, D, C]// 从subList删除数据subList.remove("A");System.out.println("sublist3:" + subList);      // sublist3:[B, D]System.out.println("list3:" + list);        // list3:[B, D, C]}

参考源码注释:ArrayList.subList()
ArrayList-subList.png

6.【强制】使用 Map 的方法 keySet() / values() / entrySet() 返回集合对象时,不可以对其进行添加元素操作

详细:使用 Map 的方法 keySet() / values() / entrySet() 返回集合对象时,不可以对其进行添加元素操作,否则会抛出 UnsupportedOperationException 异常。

返回的集合是内部类,不是我们想当然以为的实现类本身,并且该内部类没有实现添加方法

Map.keySet():
Map-keySet.png
HashMap.values():
HashMap-values.png

7.【强制】Collections 类返回的集合对象,很多都不可进行添加或删除

详细:Collections 类返回的对象,如:emptyList() / singletonList() 等都是 immutable list,不可 对其进行添加或者删除元素的操作。

同上,返回的集合对象很多是内部类,里面并没有实现添加、删除方法

Collections.emptyList():
Collections-emptyList.png

8.【强制】在 subList 场景中,高度注意对父集合元素的增加或删除

详细:在 subList 场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。

父集合的增加、删除会触发子列表的操作,最后抛出异常

@Testpublic void subListTest() {List list = new ArrayList<>(3);list.add("A");list.add("B");list.add("C");System.out.println("list:" + list);List subList = list.subList(0, 2);System.out.println("sublist:" + subList);// 给list添加数据System.out.println("=====对list操作=====");list.add("E");      // 抛出异常 'java.util.ConcurrentModificationException'System.out.println("sublist4:" + subList);System.out.println("list4:" + list);}

9.【强制】用集合转数组的方法,使用toArray(T[]),且传入参数为0的空数组

详细:使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为 0 的空数组。
说明1:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误
说明2:使用 toArray 带参方法,数组空间大小的 length:
1)等于 0,动态创建与 size 相同的数组,性能最好。
2)大于 0 但小于 size,重新创建大小等于 size 的数组,增加 GC 负担。
3)等于 size,在高并发情况下,数组创建完成之后,size 正在变大的情况下,负面影响与 2 相同。
4)大于 size,空间浪费,且在 size 处插入 null 值,存在 NPE 隐患。

// ArrayList.toArray()
public Object[] toArray() {return Arrays.copyOf(elementData, size);}

10.【强制】使用 Collection 接口任何实现类的 addAll() 方法时,要对输入的集合参数进行 NPE 判断。

// ArrayList.addAll()
public boolean addAll(Collection c) {Object[] a = c.toArray();  // 对象调用方法,必须非空int numNew = a.length;ensureCapacityInternal(size + numNew);  // Increments modCountSystem.arraycopy(a, 0, elementData, size, numNew);size += numNew;return numNew != 0;}

11.【强制】使用Arrays.asList(),不能使用修改等相关方法

详细:使用工具类 Arrays.asList() 把数组转换成集合时,不能使用其修改集合相关的方法,它的 add / remove / clear 方法会抛出 UnsupportedOperationException 异常。

asList方法返回的只是一个内部类,该内部类中并未实现add/remove等操作集合的方法

Arrays.asList():
Arrays-asList.png

12.【强制】泛型通配符不能使用 add 方法, 而不能使用 get 方法

详细:泛型通配符来接收返回的数据,此写法的泛型集合不能使用 add 方法, 而不能使用 get 方法
说明:扩展说一下 PECS(Producer Extends Consumer Super) 原则,即频繁往外读取内容的,适合用,经常往里插入的,适合用

PECS:生产者使用泛型上界通配符,消费者使用泛型下界通配符
详细参考地址

13.【强制】无泛型限制定义的集合赋值时要进行对象类型判断

详细:在无泛型限制定义的集合赋值给泛型限制的集合时,在使用集合元素时,需要进行 instanceof 判断,避免抛出 ClassCastException 异常。

    @Testpublic void genericTest(){// 定义泛型System.out.println("====定义泛型的list====");List list = new ArrayList<>(2);// 无定义泛型List list2 = new ArrayList<>(3);list2.add("mango");list2.add("cheng");list2.add(new Person());// 赋值list = list2;// 取非泛型值:抛异常String s = list.get(2);}

14.【强制】不要在 foreach 循环里进行元素的 remove / add 操作

详细:不要在 foreach 循环里进行元素的 remove / add 操作。remove 元素请使用 iterator 方式, 如果并发操作,需要对 iterator 对象加锁。
详细参考地址

foreach是增强for循环,底层实现依赖迭代器,再循环中进行删除元素时,特定情况下会抛出异常

@Testpublic void foreachTest() {List list = new ArrayList(2);list.add("1");list.add("2");for (String item : list) {// 删除1正常;删除2抛异常if ("1".equals(item)) {list.remove(item);}}System.out.println(list);}

15.【强制】JDK7 版本及以上,Comparator 实现类注意

详细:在 JDK7 版本及以上,Comparator 实现类要满足如下三个条件,不然 Arrays.sort,Collections.sort 会抛 IllegalArgumentException 异常。
说明:三个条件如下
1)x,y 的比较结果和 y,x 的比较结果相反。
2)x > y,y > z,则 x > z。
3)x = y,则 x,z 比较结果和 y,z 比较结果相同。

反例:下例中没有处理相等的情况,交换两个对象判断结果并不互反,不符合第一个条件,在实际使用中可能会出现异 常。

new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return o1.getId() > o2.getId() ? 1 : -1;
}
};

Comparator实现类注意相等的情况,两个值相等时比较结果要一致

16.【推荐】泛型集合使用时,在 JDK7 及以上,使用 diamond 语法或全省略。

说明:菱形泛型,即 diamond,直接使用<>来指代前边已经指定的类型。

使用泛型创建对象时,前面已经定义了类型,则后面省略

17.【推荐】集合初始化时,指定集合初始值大小。

说明:HashMap 使用构造方法 HashMap(int initialCapacity) 进行初始化时,如果暂时无法确定集合大小,那么指定默认值(16)即可。
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loaderfactor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。
反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素增加而被迫不断扩容,resize() 方法总共会调用 8 次,反复重建哈希表和数据迁移。当放置的集合元素个数达千万级时会影响程序性能。

涉及集合内部的扩容机制

18.【推荐】使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历

说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key 所对应的 value。而entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.forEach 方法。

entrySet存储了Map.Entry,包含了键、值;keySet仅包含键

// HashMap.entrySet()
public Set> entrySet() {Set> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}

19.【推荐】高度注意 Map 类集合 K / V 能不能存储 null 值的情况

集合类KeyValue说明
HashTable不为null不为null线程安全
TreeMap不为null可为null线程不安全
ConcurrentHashMap不为null不为null线程安全-锁分段技术(JDK8:CAS)
HashMap可为null可为null线程不安全

20.【参考】合理利用好集合的有序性和稳定性

详细:合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响

21.【参考】利用 Set 元素唯一的特性

详细:利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的contains() 进行遍历去重或者判断包含操作。

在使用时,如果需要存储的数据需要唯一的,则优先考虑使用Set

相关内容

热门资讯

百年校庆贺词 百年校庆贺词梦圆百年____太和二小百年校庆致词第一章 世纪回眸一百年,那是斗转星移的一百年;一百年...
情人节祝福 关于情人节祝福(精选50句)  曾经我把一份甜蜜种在了金色的土地,现在我想摘下一份晶莹在这收获的季节...
通用祝春节快乐的祝福语短信 2020年通用祝春节快乐的祝福语短信集合22句  太阳一升一落,年已悄然离去。眼睛一睁一闭,付出收获...
本命年过生日的祝福语 本命年过生日的祝福语(精选50句)  在平凡的学习、工作、生活中,大家都有写祝福语的经历,对祝福语很...
外婆生日祝福语 外婆生日祝福语大全  在生活、工作和学习中,大家都用到过祝福语吧,根据祝愿的对象不同,祝福语分为吉日...
祝公司发展的祝福短语 祝公司发展的祝福短语(精选80条)  祝愿您的公司,新年好!新年新面貌!新年新开始!新年新运气!新朋...
发给领导的新年祝福语 发给领导的新年祝福语  在学习、工作或生活中,许多人都写过祝福语吧,祝福语是人们表达心中祝福的话语。...
平安夜祝福语 平安夜祝福语(精选100句)  快乐为你欢笑,幸福为你舞蹈,吉祥为你奔跑,温馨拉着你的手,连苹果都把...
通用春节祝福语 2020年通用春节祝福语大汇总67条  一家和和睦睦,一年开开心心,一生高高兴兴,一世平平安安,天天...
母亲节卡片祝福语英文 母亲节卡片祝福语英文在这一天祝福自己的妈妈,让她知道你在想着她,记挂着她。to the world’...
圣诞节的祝福语 关于圣诞节的祝福语(精选155句)  在学习、工作或生活中,大家都用到过祝福语吧,借助祝福语人们可以...
温馨七夕祝福语短信摘录 温馨七夕祝福语短信摘录19条  小懒猫,睡得香呢?今天是七夕哦!要想我哦!七夕情人节快乐!以下是小编...
对长辈的祝福语 对长辈的祝福语  在学习、工作或生活中,大家都写过祝福语吧,根据祝愿的对象不同,祝福语分为吉日喜庆祝...
谷雨渔民节的祝福语 谷雨渔民节的祝福语(精选65句)  在日常学习、工作抑或是生活中,大家或多或少都会用到过祝福语吧,根...
写送行的祝福语 关于写送行的祝福语77句  携一缕快乐阳光,同学情谊绵绵长;唱一路纯真梦想,埋头苦读书香傍。四年时光...
感谢朋友们的祝福语 感谢朋友们的祝福语(精选265句)  在学习、工作或生活中,许多人都有过写祝福语的经历,对祝福语都不...
温馨感恩节祝福语短信 温馨感恩节祝福语短信集合40条  花朵感恩雨露的滋养,绚丽绽放;鸟儿感恩树木的怀抱,放声歌唱;白云感...
生日暖心的祝福语 生日暖心的祝福语  在生活、工作和学习中,大家都经常接触到祝福语吧,祝福语可以传达对他人的关切和问候...
祝妇女节快乐的祝福语微信 2020年祝妇女节快乐的祝福语微信集锦40句  女人如花,绚丽多彩;女人如水,温柔恬淡;女人如诗,迷...
下雨的周末祝福短信 下雨的周末祝福短信  周末到了,放松的日子里,请别再忙碌,收到短信,为你送上温暖贴心;我的绵绵情意,...