ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 五、 集合处理 * 【**强制**】关于hashCode和equals的处理,遵循如下规则: - 重写equals就必须重写hashCode,以保证equals相等则hashCode一定相等,hashCode不等则equals一定不等。 - Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。 - 如果自定义对象做为Map的键,也必须重写hashCode和equals。 正例: String重写了hashCode和equals方法,所以可以放心地使用String对象作为key。 * * * * * * 【**强制**】 ArrayList的subList结果不可强转成ArrayList,否则会抛ClassCastException异常: java.util.RandomAccessSubList cannot be cast to java.util.ArrayList 因为,subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 类型 ,而是 ArrayList 的一个视图。 需要注意的是,对原集合进行结构修改,会导致subList在遍历、增加、删除时产生ConcurrentModificationException 异常。 * * * * * * 【**强制**】集合转数组时,必须使用集合的toArray(T[] array),传入类型一致的数组,大小就是list.size()。 反例: 直接使用toArray无参方法存在问题,此方法只能返回Object[]类型,若强转其它类型数组将抛ClassCastException异常。 正例: ~~~ List<String> list = new ArrayList<String>(2); list.add("guan"); list.add("bao"); String[] array = new String[list.size()]; array = list.toArray(array); ~~~ 说明:使用toArray带参方法,入参分配的数组空间不够大时,toArray方法内部将重新分配内存空间,并返回新数组地址;如果数组空间大于实际所需,则下标为[list.size()]的数组元素将被置为null,之后多余的数组元素保持原值。因此最好将入参数组大小定义为与集合元素个数相等。 * * * * * * 【**强制**】使用工具类Arrays.asList()将数组转为集合时,不能使用该集合的add/remove/clear等修改集合的方法,会抛出UnsupportedOperationException异常。 因为,asList返回对象是Arrays的内部类,该类并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。 例如: ~~~ String[] str = new String[] { "a", "b" }; List list = Arrays.asList(str); list.add("c"); //运行时异常。 str[0]= "gujin"; //那么list.get(0)也会随之修改。 ~~~ * * * * * * 【**强制**】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。 反例: ~~~ List<String> a = new ArrayList<String>(); a.add("1"); a.add("2"); for (String temp : a) { if("1".equals(temp)){ a.remove(temp); } } ~~~ 正例: ~~~ Iterator<String> it = a.iterator(); while(it.hasNext()){ String temp = it.next(); if(删除元素的条件){ it.remove(); } } ~~~ * * * * * * 【**强制**】 JDK7版本以上,Comparator需满足自反性、传递性和对称性,否则Arrays.sort、Collections.sort会报IllegalArgumentException异常。说明: - 自反性:x,y的比较结果与y,x的比较结果相反。 - 传递性:x>y, y>z, 则x>z。 - 对称性:x=y, 则x,z比较结果和y,z比较结果相同。 反例:下例中没有处理相等的情况,实际使用中可能会出现异常</font> ~~~ new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getId() > o2.getId() ? 1 : -1; } } ~~~ * * * * * * 【推荐】使用entrySet遍历Map类KV集合,而不是keySet方式遍历。 因为,keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。 正例:keySet()返回的是K值集合,是一个Set集合对象;values()返回的是V值集合,是一个list集合对象;entrySet()返回的是K-V值组合集合。 * * * * * * 【推荐】高度注意Map类集合K/V能不能存储null值的情况,如下表格: | 集合类 | Key | Value | Super | 说明 | | --- | --- | --- | --- | --- | | Hashtable | 不允许为null | 不允许为null | Dictionary | 线程安全 | | ConcurrentHashMap | 不允许为null | 不允许为null | AbstractMap | 分段锁技术 | | TreeMap | 不允许为null | 允许为null | AbstractMap | 线程不安全 | | HashMap | 允许为null | 允许为null | AbstractMap | 线程不安全 | 反例: 注意,HashMap允许放入null值,但ConcurrentHashMap却不可以,否则会抛出空指针异常! * * * * * * 【参考】合理利用集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。 说明:稳定性指集合每次遍历的元素次序是一定的。有序性是指遍历的结果是按某种比较规则顺序排列的。 例如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。