java集合相关问题
1.Map/Set 的 key 为自定义对象时,必须重写 hashCode 和 equals;
2.ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList ;
说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上;
在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、 删除均产生 ConcurrentModificationException 异常;
3.使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全 一样的数组,大小就是 list.size()。
直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误;
4.使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法, 它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常;
原因:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组;下面的代码为Arrays内部类,其中没有实现list接口的相关集合操作方法:
1 private static class ArrayList<E> extends AbstractList<E> 2 implements RandomAccess, java.io.Serializable 3 { 4 private static final long serialVersionUID = -2764017481108945198L; 5 private final E[] a; 6 7 ArrayList(E[] array) { 8 if (array==null) 9 throw new NullPointerException(); 10 a = array; 11 } 12 13 public int size() { 14 return a.length; 15 } 16 17 public Object[] toArray() { 18 return a.clone(); 19 } 20 21 public <T> T[] toArray(T[] a) { 22 int size = size(); 23 if (a.length < size) 24 return Arrays.copyOf(this.a, size, 25 (Class<? extends T[]>) a.getClass()); 26 System.arraycopy(this.a, 0, a, 0, size); 27 if (a.length > size) 28 a[size] = null; 29 return a; 30 } 31 32 public E get(int index) { 33 return a[index]; 34 } 35 36 public E set(int index, E element) { 37 E oldValue = a[index]; 38 a[index] = element; 39 return oldValue; 40 } 41 42 public int indexOf(Object o) { 43 if (o==null) { 44 for (int i=0; i<a.length; i++) 45 if (a[i]==null) 46 return i; 47 } else { 48 for (int i=0; i<a.length; i++) 49 if (o.equals(a[i])) 50 return i; 51 } 52 return -1; 53 } 54 55 public boolean contains(Object o) { 56 return indexOf(o) != -1; 57 } 58 }
5.不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁;
这是因为在foreach循环里如果使用 remove/add 操作会改变集合大小从而导致循环报错;
6.使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。
说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key
所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更
高。如果是 JDK8,使用 Map.foreach 方法。
7.利用 Set 元素唯一的特性,可以快速对另一个集合进行去重操作,避免使用 List 的contains 方法进行遍历去重操作。