Collection和Collections的区别

  1. 简介

    Collection是接口,抽象了集合向外暴露的一些方法,同时继承了Iterable迭代器模式。

    Collections是工具类,封装了常见对集合操作的方法。

  2. 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);
    }
    
  3. Collections常见方法

    1. 空集合(常量和方法)

      // 方法中经常需要对集合进行非空判断,如果被调用方法返回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;
       }
      ……
      
    2. 检查

      //传入任何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;
      }
      
    3. 排序

      // 该列表必须是可修改的,但无需调整大小。
      // 如果指定的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;
      }
      
    4. 运算

      // 将所有指定的元素添加到指定的集合中。要添加的元素可以单独指定或作为数组指定。此方法的行为与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]);
              }
          }
      }
      
    5. 大小值

      // 根据其元素的自然顺序,返回给定集合的最大元素。集合中的所有元素都必须实现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;
      }
      
    6. 同步

      // 返回指定的集合的同步(线程安全)集合。为了保证串行访问,至关重要的是通过返回的集合完成对集合的所有访问。
      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));
      }
      
    7. 不变性

      // 返回指定集合的不可修改视图。该方法允许模块为用户提供对内部集合的“只读”访问。直接或通过其迭代器修改动作会抛出UnsupportedOperationException 
      public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
          return new UnmodifiableCollection<>(c);
      }
      
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值