-
简介
Collection是接口,抽象了集合向外暴露的一些方法,同时继承了Iterable迭代器模式。
Collections是工具类,封装了常见对集合操作的方法。
-
Collection常见方法
// 返回此集合中的元素数。如果此集合包含超过Integer.MAX_VALUE元素,则返回Integer.MAX_VALUE public int size(); // 如果此集合不包含任何元素,则返回true public boolean isEmpty(); // 如果此集合包含指定的元素,则返回 true。更正式地讲,当且仅当此集合包含至少一个元素e使得(o == null?e == null: o.equals(e)),则返回 true public boolean contains(Object o); // 返回此集合中元素的迭代器。没有关于元素返回顺序的保证(除非此集合是提供顺序保证的某些类的实例)。 public Iterator iterator(); // 返回一个包含此集合中所有元素的数组。如果此集合存在其元素由其迭代器返回的顺序保证,则此方法必须按相同的顺序返回元素。 // 返回的数组是“安全的”,因为此集合不会维护对其的任何引用。(换句话说,该方法返回了一个新数组)。因此,调用者可以自由修改返回的数组。 // 该方法充当了基于数组的API与基于集合的API之间的桥梁。 public Object[] toArray(); // 确保此集合包含指定的元素(可选操作)。如果此集合由于调用结果而更改,则返回true。 (如果此集合不允许重复并且已经包含指定的元素,则返回false // 支持此操作的集合可能会对可以添加到此集合中的元素施加限制。特别是,某些集合将拒绝添加null元素,而另一些将对可能添加的元素类型施加限制 // 如果某个集合出于某种原因拒绝添加特定元素(除了已经包含该元素之外),它必须抛出一个异常。 public boolean add(Object o); // 从此集合中删除指定元素的单个实例(如果存在)(可选操作)。 // 更正式地讲,如果此集合包含一个或更多此类元素,删除使得(o == null?e == null:o.equals(e))成立的元素e //如果此集合包含指定的元素,则返回true public boolean remove(Object o); // 将指定集合中的所有元素添加到该集合中。 // 如果在操作进行过程中修改了指定的集合,则该操作的行为是不确定的 public boolean addAll(Collection c); // 从此集合中删除所有元素。此方法返回后,集合将为空。 public void clear(); // 仅保留此集合中包含在指定集合中的元素)。换句话说,从该集合中删除所有未包含在指定集合中的元素。 public boolean retainAll(Collection c); // 删除所有包含在指定集合中的元素。此调用返回后,此集合将不包含与指定的集合相同的元素。 public boolean removeAll(Collection c); // 如果此集合包含指定集合中的所有元素,true public boolean containsAll(Collection c); // 返回一个包含此集合中所有元素的数组;返回数组的类型是指定数组的运行时类型。如果没有传入合适大小的数组,将使用指定数组的运行时类型和此集合的大小分配一 // 个新数组,其他同toArray()方法一致 public T[] toArray(Object[] a); }
-
Collections常见方法
-
空集合(常量和方法)
// 方法中经常需要对集合进行非空判断,如果被调用方法返回null就会多一次判断,这时候如果返回一个空集合就会更优雅。但是如果每次都要new ArrayList都会有一个初始化空间,占用内存资源,积少成多会浪费很多的资源,Collections中的空集合对象是一个用静态常量,在内存中只存在一份,所以能够节省内存资源。 // 注意: 我们在使用emptyList空的方法返回空集合的时候要注意,这个空集合是不可变的。 public static final List EMPTY_LIST = new EmptyList<>(); public static final Map EMPTY_MAP = new EmptyMap<>(); public static final Set EMPTY_SET = new EmptySet<>(); //Collections出了上述常量外,还有需要方法。若是不需要泛型的地方可以直接使用常量 ,若是需要泛型的地方就需要使用方法。 public static final <T> List<T> emptyList() { return (List<T>) EMPTY_LIST; } ……
-
检查
//传入任何Collection子类,返回一个检查Collection对象 publicstatic<E>Collection<E>checkedCollection(Collection<E>c,Class<E>type) //传入ArrayList、LinkedList,返回检查的List publicstatic<E>List<E>checkedList(List<E>list,Class<E>type) //传入HashSet,返回检查Set publicstatic<E>Set<E>checkedSet(Set<E>s,Class<E>type) //传入TreeSet,返回检查SortedSet publicstatic<E>SortedSet<E>checkedSortedSet(SortedSet<E>s,Class<E>type) //传入HashMap,返回检查Map publicstatic<K,V>Map<K,V>checkedMap(Map<K,V>m,Class<K>keyType,alueType) //传入TreeMap,返回检查SortedMap publicstatic<K,V>SortedMap<K,V>checkedSortedMap(SortedMap<K,V>m, Class<K>keyType,Class<V>valueType)
大家都知道java的数组是动态类型安全的,因为数组在创建时就已经记住了其数组元素的类型,所以不管数组的引用怎么协变,如果插入不符合正确类型的对象了,数组就会报错。
而java的泛型容器相比就显得很脆弱,因为插入元素时的检查仅仅存在于编译期,其实就是根据引用的类型来的,换句话说,普通的泛型容器根本没记住创建时你给定的类型参数。所以Collections定义了一些类型安全方法,在插入时检查数据类型,调高了代码质量。
public boolean add(E e) { return c.add(typeCheck(e)); } E typeCheck(Object o) { if (o != null && !type.isInstance(o)) throw new ClassCastException(badElementMsg(o)); return (E) o; }
-
排序
// 该列表必须是可修改的,但无需调整大小。 // 如果指定的Comparator为null,则此列表中的所有元素都必须实现Comparable接口来实现自然排序。 // 默认实现获取一个包含此列表中所有元素的数组,对该数组进行排序,并在此列表上进行迭代,从数组中的相应位置重置每个元素。 // 此实现是一种稳定,自适应,迭代的合并排序,当对输入数组进行部分排序时,所需的比较远远少于n lg(n)个比较,而当对输入数组进行随机排序时,则提供了传统的mergesort的性能。如果输入数组几乎被排序,则该实现需要大约n个比较。临时存储要求从较小的常量(对于几乎排序的输入数组)到n / 2个对象引用(对于随机有序的输入数组)不等 // 该实现在其输入数组中利用了升序和降序的同等优势,并且可以在同一输入数组的不同部分中利用了升序和降序的优势。它非常适合合并两个或多个排序后的数组:简单地将数组连接起来并对结果数组进行排序。 default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } }
public static <T> void sort(T[] a, Comparator<? super T> c) { if (c == null) { sort(a); } else { if (LegacyMergeSort.userRequested) legacyMergeSort(a, c); else TimSort.sort(a, 0, a.length, c, null, 0, 0); } }
private static <T> void legacyMergeSort(T[] a, Comparator<? super T> c) { T[] aux = a.clone(); if (c==null) mergeSort(aux, a, 0, a.length, 0); else mergeSort(aux, a, 0, a.length, 0, c); }
public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a); else ComparableTimSort.sort(a, 0, a.length, null, 0, 0); }
private static void legacyMergeSort(Object[] a) { Object[] aux = a.clone(); mergeSort(aux, a, 0, a.length, 0); }
private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off) { int length = high - low; // Insertion sort on smallest arrays if (length < INSERTIONSORT_THRESHOLD) { for (int i=low; i<high; i++) for (int j=i; j>low && ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--) swap(dest, j, j-1); return; } // Recursively sort halves of dest into src int destLow = low; int destHigh = high; low += off; high += off; int mid = (low + high) >>> 1; mergeSort(dest, src, low, mid, -off); mergeSort(dest, src, mid, high, -off); // If list is already sorted, just copy from src to dest. This is an // optimization that results in faster sorts for nearly ordered lists. if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) { System.arraycopy(src, low, dest, destLow, length); return; } // Merge sorted halves (now in src) into dest for(int i = destLow, p = low, q = mid; i < destHigh; i++) { if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0) dest[i] = src[p++]; else dest[i] = src[q++]; } } /** * Swaps x[a] with x[b]. */ private static void swap(Object[] x, int a, int b) { Object t = x[a]; x[a] = x[b]; x[b] = t; }
-
运算
// 将所有指定的元素添加到指定的集合中。要添加的元素可以单独指定或作为数组指定。此方法的行为与c.addAll(Arrays.asList(elements))的行为相同,但是该方法可能在大多数实现中运行得明显更快。 public static <T> boolean addAll(Collection<? super T> c, T... elements) { boolean result = false; for (T element : elements) result |= c.add(element); return result; }
// 将所有元素从一个列表复制到另一个列表。 操作之后,目标列表中每个复制元素的索引将与源列表中其索引相同。目标列表必须至少与源列表一样长。如果更长,则目标列表中的剩余元素将不受影响。该方法执行效率是线性时间。 public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); // 目标列表必须比源列表长 if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); // 目标列表小于10,或者目标列表与源列表都为RandomAccess类型则遍历插入 // RandomAccess接口是一个标记接口,用以标记实现的List集合具备快速随机访问的能力。 // 当一个List拥有快速访问功能时,其遍历方法采用for循环最快速。而没有快速访问功能的List,遍历的时候采用Iterator迭代器最快速。 if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { // 否则使用迭代器模式遍历插入 ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
// 如果两个指定的集合没有共同的元素,则返回true // 两个集合必须使用相同的相等性检测,允许在两个参数中传递相同的集合,在这种情况下,当且仅当集合为空时,该方法才返回true public static boolean disjoint(Collection<?> c1, Collection<?> c2) { // 用于contains()的集合。优先考虑包含contains()的集合具有较低的O()复杂度。 Collection<?> contains = c2; // 要迭代的集合。如果集合的contains()实现具有不同的O()复杂度,则将使用较慢 contains()的集合进行迭代。对于 contains()具有相同复杂度的集合,通过迭代较小的集合可以达到最佳性能。 Collection<?> iterate = c1; // 性能优化方案:// 1.通常在c1上迭代。 2.如果c1是Set,则迭代c2。 3.如果任何一个集合为空,则结果始终为true。4.遍历较小的Collection。 if (c1 instanceof Set) { // 使用c1作为contains,因为Set的contains()的性能要好于O(N / 2) iterate = c2; contains = c1; } else if (!(c2 instanceof Set)) { // 两者都是集合则遍历较小的集合。如果c1包含3个元素,并且c2包含50个元素,并且假设contains()需要ceiling(N / 2)次比较,那么检查c2中的所有c1元素将需要进行75个比较(3 * ceiling( 50/2))VS 检查c1中的所有c2元素将需要进行100次比较(50 * ceiling(3/2))。 int c1size = c1.size(); int c2size = c2.size(); if (c1size == 0 || c2size == 0) { // 存在有一个集合为空则什么都不会匹配。 return true; } if (c1size > c2size) { iterate = c2; contains = c1; } } for (Object e : iterate) { if (contains.contains(e)) { // Found a common element. Collections are not disjoint. return false; } } // No common elements were found. return true; }
// 用指定的元素替换指定列表中的所有元素。 public static <T> void fill(List<? super T> list, T obj) { int size = list.size(); // 目标列表小于25,或者目标列表为RandomAccess类型则遍历插入 // 当一个List拥有快速访问功能时,其遍历方法采用for循环最快速。而没有快速访问功能的List,遍历的时候采用Iterator迭代器最快速。 if (size < FILL_THRESHOLD || list instanceof RandomAccess) { for (int i=0; i<size; i++) list.set(i, obj); } else { ListIterator<? super T> itr = list.listIterator(); for (int i=0; i<size; i++) { itr.next(); itr.set(obj); } } }
// 返回指定集合中等于指定对象的元素数。更正式地,返回集合中元素e的数量,使得(o == null?e == null:o.equals(e)) public static int frequency(Collection<?> c, Object o) { int result = 0; if (o == null) { for (Object e : c) if (e == null) result++; } else { for (Object e : c) if (o.equals(e)) result++; } return result; }
// 返回指定源列表中指定目标列表首次出现的起始位置;如果不存在则返回-1。更正式地,返回最低的索引i使得source.subList(i,i + target.size()).equals(target),或-1(如果没有)这样的索引。(如果target.size()> source.size(),则返回-1) public static int indexOfSubList(List<?> source, List<?> target) { int sourceSize = source.size(); int targetSize = target.size(); int maxCandidate = sourceSize - targetSize; // 目标列表小于35,或者目标列表与源列表都为RandomAccess类型则遍历插入 // 当一个List拥有快速访问功能时,其遍历方法采用for循环最快速。而没有快速访问功能的List,遍历的时候采用Iterator迭代器最快速。 if (sourceSize < INDEXOFSUBLIST_THRESHOLD || (source instanceof RandomAccess&&target instanceof RandomAccess)) { nextCand: for (int candidate = 0; candidate <= maxCandidate; candidate++) { for (int i=0, j=candidate; i<targetSize; i++, j++) if (!eq(target.get(i), source.get(j))) continue nextCand; // Element mismatch, try next cand return candidate; // All elements of candidate matched target } } else { // Iterator version of above algorithm ListIterator<?> si = source.listIterator(); nextCand: for (int candidate = 0; candidate <= maxCandidate; candidate++) { ListIterator<?> ti = target.listIterator(); for (int i=0; i<targetSize; i++) { if (!eq(ti.next(), si.next())) { // Back up source iterator to next candidate for (int j=0; j<i; j++) si.previous(); continue nextCand; } } return candidate; } } return -1; // No candidate matched the target }
// 将列表中所有出现的一个指定值替换为另一个 public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) { boolean result = false; int size = list.size(); // 目标列表小于11,或者目标列表与源列表都为RandomAccess类型则遍历插入 // 当一个List拥有快速访问功能时,其遍历方法采用for循环最快速。而没有快速访问功能的List,遍历的时候采用Iterator迭代器最快速。 if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) { if (oldVal==null) { for (int i=0; i<size; i++) { if (list.get(i)==null) { list.set(i, newVal); result = true; } } } else { for (int i=0; i<size; i++) { if (oldVal.equals(list.get(i))) { list.set(i, newVal); result = true; } } } } else { ListIterator<T> itr=list.listIterator(); if (oldVal==null) { for (int i=0; i<size; i++) { if (itr.next()==null) { itr.set(newVal); result = true; } } } else { for (int i=0; i<size; i++) { if (oldVal.equals(itr.next())) { itr.set(newVal); result = true; } } } } return result; }
// 反转指定列表中元素的顺序。此方法以线性时间运行。 public static void reverse(List<?> list) { int size = list.size(); // 目标列表小于18,或者目标列表与源列表都为RandomAccess类型则遍历插入 // 当一个List拥有快速访问功能时,其遍历方法采用for循环最快速。而没有快速访问功能的List,遍历的时候采用Iterator迭代器最快速。 if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) { for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--) swap(list, i, j); } else { ListIterator fwd = list.listIterator(); ListIterator rev = list.listIterator(size); for (int i=0, mid=list.size()>>1; i<mid; i++) { Object tmp = fwd.next(); fwd.set(rev.previous()); rev.set(tmp); } } } public static void swap(List<?> list, int i, int j) { final List l = list; l.set(i, l.set(j, l.get(i))); } public E set(int index, E element) { E oldValue = a[index]; a[index] = element; return oldValue; }
// 使用指定的随机数随机打乱指定的列表,所有排列均以相同的可能性。 // 此实现从最后一个元素到第二个元素向后遍历该列表,从列表的第一个元素到当前位置随机选择元素重复交换为“当前位置” // 此方法以线性时间运行。如果指定的列表没有实现RandomAccess接口并且很大,则在打乱之前将指定的列表转储到数组中,然后将经过改组的数组转回到列表中。这避免了因将“顺序访问”列表改组到位而导致的二次行为。 public static void shuffle(List<?> list, Random rnd) { int size = list.size(); if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) { for (int i=size; i>1; i--) swap(list, i-1, rnd.nextInt(i)); } else { Object arr[] = list.toArray(); // Shuffle array for (int i=size; i>1; i--) swap(arr, i-1, rnd.nextInt(i)); // Dump array back into list // instead of using a raw type here, it's possible to capture // the wildcard but it will require a call to a supplementary // private method ListIterator it = list.listIterator(); for (int i=0; i<arr.length; i++) { it.next(); it.set(arr[i]); } } }
-
大小值
// 根据其元素的自然顺序,返回给定集合的最大元素。集合中的所有元素都必须实现Comparable接口。此外,集合中的所有元素都必须是相互可比较的(即对于集合中的任何元素e1和e2,e1.compareTo(e2)不得抛出ClassCastExceptio)。 public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) { Iterator<? extends T> i = coll.iterator(); T candidate = i.next(); while (i.hasNext()) { T next = i.next(); if (next.compareTo(candidate) > 0) candidate = next; } return candidate; }
// 根据其元素的自然顺序,返回给定集合的最小元素。集合中的所有元素都必须实现Comparable接口。此外,集合中的所有元素都必须是相互可比较的(即对于集合中的任何元素e1和e2,e1.compareTo(e2)不得抛出ClassCastExceptio)。 public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) { Iterator<? extends T> i = coll.iterator(); T candidate = i.next(); while (i.hasNext()) { T next = i.next(); if (next.compareTo(candidate) < 0) candidate = next; } return candidate; }
-
同步
// 返回指定的集合的同步(线程安全)集合。为了保证串行访问,至关重要的是通过返回的集合完成对集合的所有访问。 public static <T> Collection<T> synchronizedCollection(Collection<T> c) { return new SynchronizedCollection<>(c); }
// 为什么要使用SynchronizedRandomAccessList // 因为它所做的全部工作就是扩展SynchronizedList和实现RandomAccess,以继承行为并将其自身标记为具有快速随机访问权限。subList出于完全相同的原因,它覆盖的唯一方法是。如果列表具有有效的随机访问权限,则其子列表也具有,因此也应该实现RandomAccess。 public static <T> List<T> synchronizedList(List<T> list) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : new SynchronizedList<>(list)); }
-
不变性
// 返回指定集合的不可修改视图。该方法允许模块为用户提供对内部集合的“只读”访问。直接或通过其迭代器修改动作会抛出UnsupportedOperationException public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) { return new UnmodifiableCollection<>(c); }
-
Collection和Collections的区别
最新推荐文章于 2023-05-25 21:38:32 发布