我所理解的JDK集合工具類

Arrays是操做數組對象的工具類,Collections是操做集合對象的工具類。Objects是操做引用數據類型對象的工具類java

Arrays的經常使用方法:python

普通排序
Arrays.sort(int[] a)
Arrays.sort(int[] a, int fromIndex, int toIndex)
其餘非boolean基礎數據類型的數組對象以及實現Comparable接口的類的數組對象均有此方法。算法

並行排序:JDK1.8新增。
Arrays.parallelSort(int[] a)
Arrays.parallelSort(int[] a, int fromIndex, int toIndex)
其餘非boolean基礎數據類型的數組對象以及實現Comparable接口的類的數組對象均有此方法。編程

並行計算:JDK1.8新增,支持函數式編程,根據傳入的方法進行一次計算。
Arrays.parallelPrefix(int[] array, IntBinaryOperator op)
Arrays.parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op)
其餘非boolean基礎數據類型的數組對象以及實現Comparable接口的類的數組對象均有此方法。數組

二分法查找:前提是該數組已經進行了排序
Arrays.binarySearch(int[] a, int key)
Arrays.binarySearch(int[] a, int fromIndex, int toIndex, int key)
其餘非boolean基礎數據類型的數組對象以及實現Comparable接口的類的數組對象均有此方法。安全

判斷兩個數組是否相等
Arrays.equals(int[] a, int[] a2)
其餘基礎數據類型的數組對象以及Object數組對象均有此方法,Object調用的是equels()方法。框架

對數組進行填充
Arrays.fill(int[] a, int val)
Arrays.fill(int[] a, int fromIndex, int toIndex, int val)
其餘基礎數據類型的數組對象以及Object數組對象均有此方法。函數式編程

複製數組
Arrays.copyOf(int[] original, int newLength),返回賦值後的數組,數組長度爲newLength。
Arrays.copyOfRange(int[] original, int from, int to)
其餘基礎數據類型的數組對象以及Object數組對象均有此方法。Object數組爲淺複製,即複製的是引用。svn

toString: 將元素用","隔開,包裹在"[ ]"內。
Arrays.toString(int[] a)
其餘基礎數據類型的數組對象以及Object數組對象均有此方法。Object數組爲引用地址。
Arrays.deepToString(Object[] a)方法內部調用了a.toString()。函數

更改元素值:JDK1.8新增,支持函數式編程
setAll(int[] array, IntUnaryOperator generator)
setAll(long[] array, IntToLongFunction generator)
setAll(double[] array, IntToDoubleFunction generator)
setAll(T[] array, IntFunction<? extends T> generator)
該類方法支持這四種類型。每種類型均有對應的並行設置方法parallelSetAll()

數組轉集合
Arrays.asList(T... a) 返回List<T>
若是是Object數組對象,該方法生成的集合對象持有的是數組對象對應元素的引用。

生成並行遍歷的Spliterator,JDK1.8新增
Arrays.spliterator(int[] array)
Arrays.spliterator(int[] array, int startInclusive, int endExclusive)
int、long、double和實現了Spliterator接口的類具備該類型方法。

生成Stream類,JDK1.8新增
Arrays.stream(int[] a)
Arrays.stream(int[] array, int startInclusive, int endExclusive)
int、long、double和實現了Stream接口的類具備該類型方法。

JDK1.8新增的方法基本都是與函數式變成或多核並行操做相關

接下來看看Arrays經常使用方法的源碼。
1,Arrays.asList()的源碼實現分析:

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);  // 爲何JDK的設計者不直接使用ava.util.ArrayList呢?
    }

這個ArrayList是數組的內部實現類,不是常常是用的java.util.ArrayList。這個內部類ArrayList是一個固定大小的list,不支持list.add()和list.remove(),這裏必定要注意。

2,Arrays.sort()的源碼實現分析:

public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

這裏用到了DualPivotQuicksort.sort()。DualPivotQuicksort是java.util包下的final類,專門用來對基礎數據類型的數據進行排序的。DualPivotQuicksort.sort()源碼分析:

static void sort(int[] a, int left, int right, int[] work, int workBase, int workLen) {
        // 對於數組長度小的狀況採用快速排序
        if (right - left < QUICKSORT_THRESHOLD) { // QUICKSORT_THRESHOLD = 286
            sort(a, left, right, true);
            return;
        }
	// 歸併+快排 (引入了TimSort的run的概念)
	...省略算法源碼
    }

快排算法sort()的源碼分析:

private static void sort(int[] a, int left, int right, boolean leftmost) {
        int length = right - left + 1;
        // 對於數組長度很小的狀況採用插入排序
        if (length < INSERTION_SORT_THRESHOLD) { // INSERTION_SORT_THRESHOLD) = 47
	    // 插入排序 insertion sort
	    ...省略算法源碼
        }
	// 雙軸快排 dual-pivot quicksort 
	...省略算法源碼(遞歸插入排序)
    }

具體的算法實現源碼不作深究,之後有機會的話寫一些關於算法拾遺。這裏主要是一些閥值要注意。

3,Arrays.sort(Object[] a)的源碼實現分析:

public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested) // 若是用戶強制要求使用傳統的排序方法。
            // -Djava.util.Arrays.useLegacyMergeSort=true 
            // 或者System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
            legacyMergeSort(a); // 使用傳統方法排序
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0); // 使用TimSort算法排序
    }

傳統的排序算法legacyMergeSort()源碼:

private static void legacyMergeSort(Object[] a, int fromIndex, int toIndex) {
        Object[] aux = copyOfRange(a, fromIndex, toIndex);
        mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
    }

    private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off) {
        int length = high - low;

        // 若是數組長度很小,採用插入排序 Insertion sort
        if (length < INSERTIONSORT_THRESHOLD) { // INSERTIONSORT_THRESHOLD = 7
            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,再進行合併排序
        ...省略算法源碼
    }

JDK1.8開始支持TimSort算法,源於Python中的TimSort(結合了merge sort 和 insertion sort)。
ComparableTimSort.sort()源碼:

static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // 數組長度爲0或1時無需排序

        // 若是數組長度小,採用無合併形式的"mini-TimSort"排序
        if (nRemaining < MIN_MERGE) { // MIN_MERGE = 32
            int initRunLen = countRunAndMakeAscending(a, lo, hi);
            binarySort(a, lo, hi, lo + initRunLen); // 二分插入排序
            return;
        }
        // 1,遍歷一遍數組,找到已經天然排序好順序的序列;3,這個序列入棧(臨時數組,排序後的數組就放在這裏);
        // 2,若是這個序列的長度 < minRun 則經過binarySort獲得長度爲minRun的序列。這個minRun的計算跟數組自己長度有關;
        // 4,一樣的方法尋找下一個分段併入另一個棧;
        // 5,合併排序兩個棧中的序列;
        // 6,重複4和5;
        ...省略算法源碼
    }

4,Arrays.parallelSort()的源碼實現分析:

public static void parallelSort(byte[] a) {
        int n = a.length, p, g;
        if (n <= MIN_ARRAY_SORT_GRAN ||
            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
            DualPivotQuicksort.sort(a, 0, n - 1);
        else
            new ArraysParallelSortHelpers.FJByte.Sorter
                (null, a, new byte[n], 0, n, 0,
                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
                 MIN_ARRAY_SORT_GRAN : g).invoke();
    }

Arrays.parallelSort()採用的是cilk排序算法
cilk排序算法基本思想:

  1. 將數組分爲兩部分;
  2. 針對每一部分:a,再分爲2部分(至關於1/4);b,針對每1/4部分進行排序;c,排序併合並這兩個1/4;
  3. 將分別排序好的這兩部分進行排序合併。

  若是當前數組的長度a.length < MIN_ARRAY_SORT_GRAN = 8192,或者當前機器不支持並行排序,則採起普通的sort()。
  ForkJoinPool.getCommonPoolParallelism()獲取當前ForkJoin線程池的並行度,跟機器的處理器核數有關,能夠經過-Djava.util.concurrent.ForkJoinPool.common.parallelism=8或者System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","8")來指定,若是=1則表示不支持並行執行。
parallelSort()的基本實現思想:

  1. 將須要被排序的數組分爲parallelism個子數組交由ForkJoin框架的每一個並行線程執行;
  2. 每一個並行線程將分配到的子數組又分爲4個子數組按照cilk算法進行排序,沒個1/4子數組都會按照DualPivotQuicksort.sort()排序;
  3. 最後將parallelism個子數組進行排序合併。

==================================華麗的分割線==================================

Collections的經常使用方法:

排序
Collections.sort(List<T> list) T或其父類須要實現Comparable接口 Collections.sort(List<T> list, Comparator<? super T> c) Collections.sort()的源碼:

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

List.sort()的源碼:

default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c); // 調用Arrays.sort()來進行排序
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

Collections.sort()最終調用的是Arrays.sort()進行排序。

查到索引
Collections.binarySearch(List<? extends Comparable<? super T>> list, T key) Collections.binarySearch(List<? extends T> list, T key, Comparator<? super T> c)

順序反轉
Collections.reverse(List<?> list)

亂序
Collections.shuffle(List<?> list)

指定元素互換
Collections.swap(List<?> list, int i, int j)

填充
Collections.fill(List<? super T> list, T obj)

複製
Collections.copy(List<? super T> dest, List<? extends T> src)

求極值
Collections.min(Collection<? extends T> coll)
Collections.min(Collection<? extends T> coll, Comparator<? super T> comp)
Collections.max(Collection<? extends T> coll)
Collections.max(Collection<? extends T> coll, Comparator<? super T> comp)

轉動元素
Collections.rotate(List<?> list, int distance)
distance能夠接受負數 將list元素總體向後移動distance的距離,原來最後的distance個元素放到最前面(有點相似與一個圓圈轉動)

替換元素
Collections.replaceAll(List<T> list, T oldVal, T newVal)

子集合索引
Collections.indexOfSubList(List<?> source, List<?> target)
Collections.lastIndexOfSubList(List<?> source, List<?> target)
若是不是子集合,返回-1

轉換爲不可變集合
Collections.unmodifiableCollection(Collection<? extends T> c)
將集合轉換爲不可變集合read-only。裝飾者模式,使用final修飾iterator,增刪元素的方法throw new UnsupportedOperationException()
Collections.unmodifiableSet(Set<? extends T> s)
Collections.unmodifiableList(List<? extends T> list)
Collections.unmodifiableMap(Map<? extends K, ? extends V> m)

轉換爲同步集合
Collections.synchronizedCollection(Collection<T> c)
Collections.synchronizedCollection(Collection<T> c, Object mutex) 指定mutex對象做爲同步鎖,將集合轉換爲線程安全的同步集合。裝飾着模式,方法內使用了 synchronized (mutex) { ... }保證線程安全
Collections.synchronizedSet(Set<T> s)
Collections.Collections.synchronizedSet(Set<T> s, Object mutex)
Collections.synchronizedList(List<T> list)
Collections.synchronizedList(List<T> list, Object mutex)
Collections.synchronizedMap(Map<K, V>)

元素受限制集合
Collections.checkedCollection(Collection<E> c, Class<E> type)
因爲JDK1.5引入了泛型,採用該方法,保證運行期集合中增長的元素只能是指定的類型。一樣是裝飾着模式。
Collections.checkedQueue(Queue<E> queue, Class<E> type)
Collections.checkedSet(Set<E>, Class<E>)
Collections.checkedList(List<E>, Class<E>)
Collections.checkedMap(Map<K, V>, Class<K>, Class<V>)

生成空的不可變集合
Collections.emptyIterator()
Collections.emptyListIterator()
Collections.emptyEnumeration()
Collections.emptySet()
Collections.emptyList()
Collections.emptyMap()

只有1個元素的不可變集合
Collections.singleton(T)
Collections.singletonList(T)
Collections.singletonMap(K, V)

擁有n個相同元素的不可變集合
Collections.nCopies(int, T)

反序比較器
Collections.reverseOrder(Comparator<T>) 返回一個Comparator<T>,返回值與參數值是相反順序的比較器

轉換爲枚舉類型的API
Collections.enumeration(Collection<T>) 返回Enumeration<T>

將Enumeration<T>轉換爲集合
Collections.list(Enumeration<T>) 返回ArrayList<T>

元素在集合中的個數
Collections.frequency(Collection<?>, Object) 返回int

兩個元素是否有交集
Collections.disjoint(Collection<?>, Collection<?>) 返回boolean

增長元素
addAll(Collection<? super T> c, T... elements)

  因爲List接口擁有listItegertor()方法,與List相關的大部分操做內部會判斷閥值,超過閥值則採用listIterator遍歷,小於閥值則採用for循環索引遍歷。不一樣的方法閥值不一樣。

==================================華麗的分割線==================================

Objects類最主要就一個方法 Objects.equals(Object a, Object b)

public static boolean equals(Object a, Object b) {
    return a == b || (a != null && a.equals(b));
  }

其他的一些好比Obejcts.isNull(Object obj)、Objects.nonNull(Ojbect obj)主要是用來在Stream流式API操做的時候使用。

相關文章
相關標籤/搜索