1.  
 【强制】关于  
 hashCode  
 和  
 equals  
 的处理,遵循如下规则:  
 
 
 1 
 ) 只要重写  
 equals 
 ,就必须重写  
 hashCode 
 。  
 
 
 2 
 ) 因为  
 Set  
 存储的是不重复的对象,依据  
 hashCode  
 和  
 equals  
 进行判断,所以  
 Set  
 存储的  
 
 
 对象必须重写这两个方法。  
 
 
 3 
 ) 如果自定义对象做为  
 Map  
 的键,那么必须重写  
 hashCode  
 和  
 equals 
 。  
 
 
 说明: 
 String  
 重写了  
 hashCode  
 和  
 equals  
 方法,所以我们可以非常愉快地使用  
 String  
 对象  
 
 
 作为  
 key  
 来使用。  
 
 
 
 2.  
 【强制】 
 ArrayList 
 的 
 subList 
 结果不可强转成 
 ArrayList 
 ,否则会抛出 
 ClassCastException  
 
 
 异常: 
 java 
 . 
 util 
 . 
 RandomAccessSubList cannot be cast to java 
 . 
 util 
 . 
 ArrayList ;  
 
 
 说明: 
 subList  
 返回的是  
 ArrayList  
 的内部类  
 SubList 
 ,并不是  
 ArrayList  
 ,而是  
 
 
 ArrayList  
 的一个视图,对于  
 SubList  
 子列表的所有操作最终会反映到原列表上。  
 
 
 
 3.  
 【强制】 在  
 subList  
 场景中, 
 高度注意 
 对原集合元素个数的修改,会导致子列表的遍历、增  
 
 
 加、删除均产生  
 ConcurrentModificationException  
 异常。  
 
 
 
 4.  
 【强制】使用集合转数组的方法,必须使用集合的  
 toArray(T[] array) 
 ,传入的是类型完全  
 
 
 一样的数组,大小就是  
 list 
 . 
 size() 
 。  
 
 
 说明: 
 使用  
 toArray  
 带参方法,入参分配的数组空间不够大时, 
 toArray  
 方法内部将重新分配  
 
 
 内存空间,并返回新数组地址 
 ; 
 如果数组元素大于实际所需,下标为 
 [ list 
 . 
 size() ] 
 的数组  
 
 
 元素将被置为  
 null 
 ,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素  
 
 
 个数一致。  
 
 
 正例:  
 
List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它
 
 类型数组将出现  
 ClassCastException  
 错误。  
 
 
 
 5.  
 【强制】使用工具类  
 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) 
  也会随之修改。  
 
 
  
  
  6.  
  【强制】泛型通配符 
  <?  
  extends T 
  > 
  来接收返回的数据,此写法的泛型集合不能使用  
  add  
  方  
 
 
  
  法,而 
  <? super T> 
  不能使用  
  get  
  方法,做为接口调用赋值时易出错。  
 
 
  
  说明: 
  扩展说一下  
  PECS(Producer Extends Consumer Super) 
  原则: 
  1 
  )频繁往外读取内容  
 
 
  
  的,适合用上界  
  Extends 
  。 
  2 
  )经常往里插入的,适合用下界  
  Super 
  。  
 
 
  
  
  7.  
  【强制】不要在  
  foreach  
  循环里进行元素的  
  remove 
  / 
  add  
  操作。 
  remove  
  元素请使用  
  Iterator  
 
 
  
  方式,如果并发操作,需要对  
  Iterator  
  对象加锁。  
 
 
  
  正例:  
 
 
 Iterator<String> it = a.iterator();
while (it.hasNext()) {
    String temp = it.next();
    if (删除元素的条件) {
        it.remove();
    }
}反例:
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
    if ("1".equals(temp)) {
        a.remove(temp);
    }
}说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的
 
  结果吗?  
 
 
  
  
  8.  
  【强制】 在  
  JDK 
  7  
  版本及以上, 
  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<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getId() > o2.getId() ? 1 : -1;
    }
};9. 【推荐】集合初始化时,指定集合初始值大小。
 
   说明: 
   HashMap  
   使用  
   HashMap(int initialCapacity)  
   初始化,  
  
 
   
   正例: 
   initialCapacity  
   =  
   ( 
   需要存储的元素个数  
   /  
   负载因子 
   ) + 1 
   。注意 
   负载因子(即  
   loader  
  
 
   
   factor 
   )默认为  
   0.75 
   , 
   如果暂时无法确定初始值大小,请设置为  
   16 
   。  
  
 
   
   反例: 
   HashMap  
   需要放置  
   1024  
   个元素,由于没有设置容量初始大小,随着元素不断增加,容  
  
 
   
   量  
   7  
   次被迫扩大, 
   resize  
   需要重建  
   hash  
   表,严重影响性能。  
  
 
   
   
   10.  
   【推荐】使用  
   entrySet  
   遍历  
   Map  
   类集合  
   KV 
   ,而不是  
   keySet  
   方式进行遍历。  
  
 
   
   说明: 
   keySet  
   其实是遍历了  
   2  
   次,一次是转为  
   Iterator  
   对象,另一次是从  
   hashMap  
   中取出  
  
 
   
   key  
   所对应的  
   value 
   。而  
   entrySet  
   只是遍历了一次就把  
   key  
   和  
   value  
   都放到了  
   entry  
   中,效  
  
 
   
   率更高。如果是  
   JDK 
   8 
   ,使用  
   Map 
   . 
   foreach  
   方法。  
  
 
   
   正例: 
   values() 
   返回的是  
   V  
   值集合,是一个  
   list  
   集合对象 
   ; 
   keySet() 
   返回的是  
   K  
   值集合,是  
  
 
   
   一个  
   Set  
   集合对象 
   ; 
   entrySet() 
   返回的是  
   K 
   - 
   V  
   值组合集合。  
  
 
   
   
   11.  
   【推荐】高度注意  
   Map  
   类集合  
   K 
   / 
   V  
   能不能存储  
   null  
   值的情况,如下表格:  
  
 
   
 
  反例: 由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,而事实上, 存储 null 值时会抛出 NPE 异常。
 
   12.  
   【参考】合理利用好集合的有序性 
   (sort) 
   和稳定性 
   (order) 
   ,避免集合的无序性 
   (unsort) 
   和  
  
 
   
   不稳定性 
   (unorder) 
   带来的负面影响。  
  
 
   
   说明: 
   有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次  
  
 
   
   序是一定的。如: 
   ArrayList  
   是  
   order 
   / 
   unsort 
   ; 
   HashMap  
   是  
   unorder 
   / 
   unsort 
   ; 
   TreeSet  
   是  
  
 
   
   order 
   / 
   sort 
   。  
  
 
   
   
   13.  
   【参考】利用  
   Set  
   元素唯一的特性,可以快速对一个集合进行去重操作,避免使用  
   List  
   的  
  
 
   
   contains  
   方法进行遍历、对比、去重操作。  
  
 
 


















