文章目錄
GitHub地址:Java-source-code-analysis
概述
Collections 類提供一些常用方法
常用方法
- addAll:將指定元素加入到指定集合中
- reverse:反轉指定 List 中元素的順序
- shuffle:對 List 集合元素進行隨機排序
- sort:排序
- swap:交換 list 中指定兩個位置的元素
- max:返回給定集合中的最大元素
- min:返回給定集合中的最小元素
- frequency:返回指定集合中指定元素的出現次數
- copy:將 src 中的內容複製到 dest 中
- replaceAll:將列表中出現的所有指定值替換爲另一個值
- binarySearch:使用二分搜索法在指定列表中搜索指定對象
- rotate:將指定列表元素按指定距離旋轉
- indexOfSubList:返回目標列表在指定列表第一次出現的起始位置,如果未找到,返回 -1
- lastIndexOfSubList:返回目標列表在指定列表最後一次出現的起始位置,如果未找到,返回 -1
- nCopies:返回 n 個指定對象的副本組成的不可變列表
- fill:將指定 list 的元素全部替換爲指定值
分類:
- 增:addAll、nCopies
- 改:reverse、shuffle、sort、swap、copy、replaceAll、rotate、fill
- 查:max、min、frequency、binarySearch、indexOfSubList、lastIndexOfSubList
1. addAll
將指定元素加入到指定集合中
聲明
public static <T> boolean addAll(Collection<? super T> c, T... elements)
參數
- c:元素要插入的集合
- elements:可變參數列表,要插入到 c 中的元素
返回值
- true:當調用該方法使集合發生變化
異常
-
UnsupportedOperationException:如果 c 不支持 add() 方法
String[] strArr = {"1","2","3"}; List<String> l1 = Arrays.asList(strArr); // 拋出UnsupportedOperationException異常,原因是asList返回的是Arrays的內部類ArrayList // 而不是 java.util.ArrayList Collections.addAll(l1, "2");
-
NullPointerException:當 c 不允許空值而 elements 含有一個或多個 null 值,另一種情況是 c 或者 elements 爲空
List<String> list = null; // 拋出NullPointerException異常,因爲list爲空 Collections.addAll(list, "1", "2", "3");
-
IllegalArgumentException:elements 中值的某些屬性不能加入 c
//TODO
使用示例
代碼
public void addAllTest() {
List<String> list = new ArrayList<>();
list.add("1");
list.add("1");
System.out.println("使用addAll之前:" + list);
boolean b = Collections.addAll(list, "2", "2");
System.out.println("使用addAll之後:" + list + ",返回值爲:" + b);
}
輸出
使用addAll之前:[1, 1]
使用addAll之後:[1, 1, 2, 2],返回值爲:true
源碼分析
public static <T> boolean addAll(Collection<? super T> c, T... elements) {
// 原始結果爲 false
boolean result = false;
// 遍歷elements可變參數列表
for (T element : elements)
// 按位或,只有同爲 false,結果才爲 false
// 只有全部 element 加入失敗,纔會返回 false
result |= c.add(element);
return result;
}
2. reverse
反轉指定 List 中元素的順序
聲明
public static void reverse(List<?> list)
參數
- list:指定被翻轉的列表
返回值
void
異常
-
UnsupportedOperationException:如果指定 list 或者其迭代器不支持 set 操作
List<String> list = Collections.nCopies(4, "hhhh"); // 拋出UnsupportedOperationException異常,nCopies返回的是一個Collections類中的靜態內部類 // 該靜態內部類不存在set方法 Collections.reverse(list);
使用示例
代碼
public void reverseTest() {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
System.out.println("使用reverse之前:" + list);
Collections.reverse(list);
System.out.println("使用reverse之後:" + list);
}
輸出
使用reverse之前:[a, b, c]
使用reverse之後:[c, b, a]
源碼分析
public static void reverse(List<?> list) {
// 得到 list 中元素個數
int size = list.size();
// private static final int REVERSE_THRESHOLD = 18;
// List 接口下的子類中,ArrayList 和 Vector 實現了 RandomAccess 接口
// 如果元素個數小於 18,或者該 List 實現了 RandomAccess 接口,就進行此類反轉
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 {
// 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 傳遞的參數是索引
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);
}
}
}
3. shuffle
對 List 集合元素進行隨機排序
聲明
public static void shuffle(List<?> list);
public static void shuffle(List<?> list, Random rnd);
參數
- list:將要進行隨機排序的列表
- rnd:指定用於隨機排列列表的隨機數
返回值
void
異常
-
UnsupportedOperationException:如果指定 list 或者其迭代器不支持 set 操作
List<String> list = Collections.nCopies(4, "hhhh"); // 拋出UnsupportedOperationException異常,nCopies返回的是一個Collections類中的靜態內部類 // 該靜態內部類不存在set方法 Collections.shuffle(list);
使用示例
代碼
public void shuffleTest() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.print("使用shuffle之前:" + list);
System.out.println();
Collections.shuffle(list);
System.out.print("使用shuffle之後:" + list);
System.out.println();
Collections.shuffle(list,new Random());
System.out.print("使用帶隨機種子的shuffle之後:" + list);
System.out.println();
Collections.shuffle(list,new Random());
System.out.print("使用帶隨機種子的shuffle之後:" + list);
}
輸出
使用shuffle之前:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
使用shuffle之後:[9, 6, 1, 8, 4, 7, 3, 2, 5, 0]
使用帶隨機種子的shuffle之後:[1, 6, 5, 9, 4, 0, 2, 3, 7, 8]
使用帶隨機種子的shuffle之後:[0, 4, 9, 7, 1, 3, 8, 2, 6, 5]
源碼分析
public static void shuffle(List<?> list) {
// private static Random r;
Random rnd = r;
// 參數如果爲空,初始化參數
if (rnd == null)
r = rnd = new Random(); // harmless race.
// 調用重載方法
shuffle(list, rnd);
}
public static void shuffle(List<?> list, Random rnd) {
// 得到元素個數
int size = list.size();
// private static final int SHUFFLE_THRESHOLD = 5;
// 元素個數小於 5,或者該 List 實現了 RandomAccess 接口,直接進行隨機打亂
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
// nextInt(i) 生成 [0,i)之間的數
// 每次 i-1 位置的數和 nextInt(i) 生成的位置的數互換
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
// 將 list 元素轉存進 arr 數組
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
// 利用迭代器把隨機排序後的數組轉存回原 list
ListIterator it = list.listIterator();
for (Object e : arr) {
it.next();
it.set(e);
}
}
}
4. sort
對指定 list 按默認升序或傳遞的比較器順序排序
聲明
public static <T extends Comparable<? super T>> void sort(List<T> list)
public static <T> void sort(List<T> list, Comparator<? super T> c)
參數
- list:要排序的列表
- c:指定列表的排序規則,如果是 null,則爲默認升序
返回值
void
異常
-
ClassCastException:如果列表中的元素不能相互比較
List list = new ArrayList<>(); list.add(1); list.add("2"); // ClassCastException String和Integer類型不可以互相比較 Collections.sort(list);
-
UnsupportedOperationException:如果指定列表的列表迭代器不支持 set 操作
// TODO
-
IllegalArgumentException:如果檢測到列表元素的自然順序違反了可比較的約定
使用示例
代碼
public void sortTest() {
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(2);
list.add(7);
System.out.println("使用sort之前:" + list);
Collections.sort(list);
System.out.println("使用sort之後:" + list);
// 降序
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println("使用sort之後:" + list);
}
輸出
使用sort之前:[5, 2, 7]
使用sort之後:[2, 5, 7]
使用sort之後:[7, 5, 2]
源碼
// Collections 中的sort
public static <T extends Comparable<? super T>> void sort(List<T> list) {
// 調用 List 接口下的sort
list.sort(null);
}
public static <T> void sort(List<T> list, Comparator<? super T> c) {
// 調用 List 接口下的sort,傳入比較器
list.sort(c);
}
// List 接口中的sort
default void sort(Comparator<? super E> c) {
// 將 list 轉存到數組中
Object[] a = this.toArray();
// 調用 Arrays 類的 sort
Arrays.sort(a, (Comparator) c);
// 調用迭代器,將排好序的數組存回 list
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
// Arrays類中的sort
public static <T> void sort(T[] a, Comparator<? super T> c) {
// 迭代器爲null時,調用不使用迭代器的方法
if (c == null) {
sort(a);
} else {
// 兼容老版本,當用戶設置時,使用
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
// 調用 TimSort 類的 sort
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
之後太複雜了,幾乎涉及了 TimSort 類的所有方法,暫時 //TODO,之後專門分析這個類
5. swap
交換指定 list 的 i、j 位置元素
聲明
public static void swap(List<?> list, int i, int j)
參數
- list:要交換位置的列表
- i:要交換的一個元素的索引值
- j:要交換的另一個元素的索引值
返回值
void
異常
-
IndexOutOfBoundsException:如果 i 或 j 超出範圍(i<0 || i>=list.size() || j<0 || j>=list.size())
List<Integer> list = new ArrayList<>(); list.add(5); // 拋出IndexOutOfBoundsException異常 Collections.swap(list,-1,5);
使用示例
代碼
public void swapTest(){
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("使用swap之前:" + list);
Collections.swap(list,0,1);
System.out.println("使用swap之後:" + list);
}
輸出
使用swap之前:[1, 2, 3, 4]
使用swap之後:[2, 1, 3, 4]
源碼分析
public static void swap(List<?> list, int i, int j) {
// 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
final List l = list;
// 被final修飾的引用本身不可改變,但是引用所指的對象可以改變
// l.get(i),得到 i 位置上的值
// l.set(j, l.get(i)),將得到的值賦值到 j 位置,並返回原來 j 位置的舊值
// l.set(i, l.set(j, l.get(i))),把得到的 j 的舊值賦值到 i 位置
l.set(i, l.set(j, l.get(i)));
}
6. max
根據元素自然順序或根據給定比較器規則返回最大值
聲明
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)
參數
- coll:要返回最大值的集合
- comp:自定義比較器
返回值
- T:給定集合按自然順序或者自定義比較器規則得到的最大值
異常
-
ClassCastException:如果集合元素間不可互相比較
HashSet integers = new HashSet<>(); integers.add(5); integers.add("3"); // 拋出ClassCastException異常,Integer和String無法比較 Collections.max(integers);
-
NoSuchElementException:如果集合爲空
HashSet integers = new HashSet<>(); // 拋出NoSuchElementException異常,集合爲空 Collections.max(integers);
使用示例
代碼
public void maxTest() {
List<Integer> list1 = new ArrayList<>();
list1.add(5);
list1.add(1);
List<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("D");
System.out.println("list1中最大值爲:" + Collections.max(list1));
System.out.println("list2中最大值爲:" + Collections.max(list2));
}
輸出
list1中最大值爲:5
list2中最大值爲:a
源碼分析
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;
}
public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
// 如果比較器爲null,調用另一個max方法
if (comp==null)
return (T)max((Collection) coll);
// 拿到迭代器
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
// 使用迭代器的 compare方法
if (comp.compare(next, candidate) > 0)
candidate = next;
}
return candidate;
}
7. min
根據元素自然順序或根據給定比較器規則返回最小值
聲明
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)
參數
- coll:要返回最小值的集合
- comp:自定義比較器
返回值
- T:給定集合按自然順序或者自定義比較器規則得到的最小值
異常
-
ClassCastException:如果集合元素間不可互相比較
HashSet integers = new HashSet<>(); integers.add(5); integers.add("3"); // 拋出ClassCastException異常,Integer和String無法比較 Collections.min(integers);
-
NoSuchElementException:如果集合爲空
HashSet integers = new HashSet<>(); // 拋出NoSuchElementException異常,集合爲空 Collections.min(integers);
使用示例
代碼
public void minTest() {
List<Integer> list1 = new ArrayList<>();
list1.add(5);
list1.add(1);
List<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("D");
System.out.println("list1中最小值爲:" + Collections.min(list1));
System.out.println("list2中最小值爲:" + Collections.min(list2));
}
輸出結果
list1中最小值爲:1
list2中最小值爲:D
源碼分析
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();
// next < candidate,更新 candidate
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
// 如果比較器爲null,使用默認自然順序取最小值
if (comp==null)
return (T)min((Collection) coll);
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
// 調用比較器的compare方法
if (comp.compare(next, candidate) < 0)
candidate = next;
}
return candidate;
}
8. frequency
返回指定集合中指定元素的出現次數
聲明
public static int frequency(Collection<?> c, Object o)
參數
- c:需要確定頻率的指定集合
- o:頻率待指定的元素
返回值
int:c 中等於 o 的元素數目
異常
-
NullPointerException:c 爲 null
ArrayList<Object> list = null; // 拋出NullPointerException異常 Collections.frequency(list,1);
使用示例
代碼
public void frequencyTest(){
List<String> list = new ArrayList<>();
list.add("A");
list.add("A");
list.add("A");
list.add("B");
list.add("B");
list.add("C");
System.out.println("使用frequency得到的結果是:" + Collections.frequency(list,"A"));
}
輸出
使用frequency得到的結果是:3
源碼分析
public static int frequency(Collection<?> c, Object o) {
int result = 0;
// 如果o爲null,判斷集合中有多少元素等於null
if (o == null) {
for (Object e : c)
if (e == null)
result++;
} else {
// 否則調用equals判等
for (Object e : c)
if (o.equals(e))
result++;
}
return result;
}
9. copy
將一個列表的所有內容複製到另一個列表中
聲明
public static <T> void copy(List<? super T> dest, List<? extends T> src)
參數
- dest:目標列表
- src:源列表
返回值
void
異常
-
IndexOutOfBoundsException:如果目標列表太小,不足以容納源列表
ArrayList<Integer> dest = new ArrayList<>(); ArrayList<Integer> src = new ArrayList<>(); src.add(1); src.add(2); // 拋出IndexOutOfBoundsException異常,因爲 dest.size()<src.size() Collections.copy(dest,src);
-
UnsupportedOperationException:如果目標列表的迭代器不支持 set 操作
//TODO
使用示例
代碼
public void copyTest(){
ArrayList<String> dest = new ArrayList<>();
ArrayList<String> src = new ArrayList<>();
dest.add("1");
dest.add("2");
dest.add("3");
src.add("6");
src.add("7");
System.out.println("未使用copy之前:" + dest);
Collections.copy(dest,src);
System.out.println("使用copy之後:" + dest);
}
輸出結果
未使用copy之前:[1, 2, 3]
使用copy之後:[6, 7, 3]
源碼分析
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");
// private static final int COPY_THRESHOLD = 10;
// 如果源列表集合大小小於10,或者源列表和目標列表都實現了RandomAccess接口
// 使用直接 set 的方式複製
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
// 從下標0開始,複製源列表到目標列表
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();
// 也是從下標0開始,將源列表複製到目標列表
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
10. replaceAll
將列表中出現的所有指定值替換爲另一個值
聲明
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
參數
- list:要進行替換的列表
- oldVal:要被替換的值
- newVal:取代oldVal的值
返回值
當list包含一個或多個oldVal時,返回"true",否則返回"false"
異常
-
UnsupportedOperationException:如果目標列表的迭代器不支持 set 操作
//TODO
使用示例
代碼
public void replaceAllTest(){
List<String> list = new ArrayList<>();
list.add("a");
list.add("a");
list.add("b");
list.add("a");
list.add("c");
System.out.println("使用replaceAll之前:" + list);
System.out.println("成功替換後返回:" + Collections.replaceAll(list,"b","h"));
System.out.println("使用replaceAll之後:" + list);
System.out.println("未成功替換時,返回:" + Collections.replaceAll(list,"b","h"));
}
輸出結果
使用replaceAll之前:[a, a, b, a, c]
成功替換後返回:true
使用replaceAll之後:[a, a, h, a, c]
未成功替換時,返回:false
源碼分析
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
// 聲明返回值爲false
boolean result = false;
// 列表大小
int size = list.size();
// private static final int REPLACEALL_THRESHOLD = 11;
// 如果列表大小小於11,或者當前list實現了RandomAccess接口
if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
// 考慮oldVal爲null的情況
if (oldVal==null) {
for (int i=0; i<size; i++) {
if (list.get(i)==null) {
// 在舊值的位置賦值新值
list.set(i, newVal);
// 返回值置爲true
result = true;
}
}
} else {
// 返回值不爲 null時,調用equals方法比較
for (int i=0; i<size; i++) {
if (oldVal.equals(list.get(i))) {
list.set(i, newVal);
result = true;
}
}
}
} else { // 列表大小大於等於11,且該list未實現RandomAccess接口,調用迭代器替換
ListIterator<T> itr=list.listIterator();
// oldVal爲null的情況
if (oldVal==null) {
for (int i=0; i<size; i++) {
if (itr.next()==null) {
itr.set(newVal);
result = true;
}
}
} else { // oldVal不爲null的情況
for (int i=0; i<size; i++) {
if (oldVal.equals(itr.next())) {
itr.set(newVal);
result = true;
}
}
}
}
return result;
}
11. binarySearch
使用二分搜素法在指定列表搜索指定對象。
在調用該方法之前,事先必須根據自然順序或比較器順序按升序排序,否則不確保能得到正確的答案。
且當列表存在等於指定對象的多個元素,則不能保證找到哪個元素
聲明
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
參數
- list:要搜索的列表
- key:要查找的元素
- c:用於排序列表的比較器
返回值
如果key存在list中,返回key所在索引;如果不存在,返回 ( - ( 插入點位置 ) - 1)
異常
-
ClassCastException:如果傳入的key與list元素不能互相比較
List list = new ArrayList<>(); list.add("1"); list.add("3"); // 拋出ClassCastException異常,Integer和String無法互相比較 Collections.binarySearch(list,2);
使用示例
代碼
public void binarySearchTest() {
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(6);
System.out.println("查找2的索引爲:" + Collections.binarySearch(list, 2));
// 如果沒找到,返回 ( -(插入點位置) - 1)
// 插入位置應該是 5,-5-1 = -6
System.out.println("查找5的索引爲:" + Collections.binarySearch(list, 5));
}
輸出結果
查找2的索引爲:2
查找5的索引爲:-6
源碼分析
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
// private static final int BINARYSEARCH_THRESHOLD = 5000;
// 如果該list實現了RandomAccess接口,或者該list的大小小於5000
// 使用索引二分搜索法
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else // 否則使用迭代器二進制搜索法
return Collections.iteratorBinarySearch(list, key);
}
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
// 如果比較器爲null,調用另一個二分搜索法
if (c==null)
return binarySearch((List<? extends Comparable<? super T>>) list, key);
// private static final int BINARYSEARCH_THRESHOLD = 5000;
// 如果該list實現了RandomAccess接口,或者該list的大小小於5000
// 使用索引二分搜索法,並傳入比較器c
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key, c);
else // 否則使用迭代器二進制搜索法,並傳入比較器c
return Collections.iteratorBinarySearch(list, key, c);
}
// 不帶比較器的indexedBinarySearch
private static <T> int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
// 二分搜索法
int low = 0;
int high = list.size()-1;
while (low <= high) {
// 中間索引
int mid = (low + high) >>> 1;
// 用list的get方法查找中間值
Comparable<? super T> midVal = list.get(mid);
// 比較中間值
int cmp = midVal.compareTo(key);
// 重置上界和下界
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
// 沒有找到元素,返回負值
return -(low + 1); // key not found
}
// 帶比較器的indexedBinarySearch
private static <T> int indexedBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
// 二分搜索法
int low = 0;
int high = l.size()-1;
while (low <= high) {
int mid = (low + high) >>> 1;
//用list的get方法查找中間值
T midVal = l.get(mid);
// 這用的是比較器的compare方法
int cmp = c.compare(midVal, key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
// 沒有找到元素,返回負值
return -(low + 1); // key not found
}
// 不帶比較器的iteratorBinarySearch
private static <T> int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
{
int low = 0;
int high = list.size()-1;
ListIterator<? extends Comparable<? super T>> i = list.listIterator();
while (low <= high) {
int mid = (low + high) >>> 1;
// 從迭代器中返回中間值
Comparable<? super T> midVal = get(i, mid);
// 比較中間值
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
// 沒有找到元素,返回負值
return -(low + 1); // key not found
}
// 帶比較器的iteratorBinarySearch
private static <T> int iteratorBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
int low = 0;
int high = l.size()-1;
ListIterator<? extends T> i = l.listIterator();
while (low <= high) {
int mid = (low + high) >>> 1;
// 從迭代器中返回中間值
T midVal = get(i, mid);
// 調用迭代器的compare方法
int cmp = c.compare(midVal, key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
// 沒有找到元素,返回負值
return -(low + 1); // key not found
}
// 從迭代器中返回中間值的方法
// 通過重定位指定列表,獲取指定位置元素
private static <T> T get(ListIterator<? extends T> i, int index) {
T obj = null;
// 返回後序調用next將返回的元素的索引
int pos = i.nextIndex();
if (pos <= index) { // 如果 pos 小,往後找
do {
obj = i.next();
} while (pos++ < index);
} else { // 如果 pos 大,往前找
do {
obj = i.previous();
} while (--pos > index);
}
// 找到值返回
return obj;
}
12. rotate
將指定列表元素按指定距離旋轉。
距離爲正時,列表元素整體向右移動,超出列表元素大小的元素依次左補齊;反之
聲明
public static void rotate(List<?> list, int distance)
參數
- list:要被旋轉的列表
- distance:要旋轉列表的距離
返回值
void
異常
-
UnsupportedOperationException:如果目標列表的迭代器不支持 set 操作
//TODO
使用示例
代碼
public void rotateTest() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.println("未使用rotate前:" + list);
Collections.rotate(list, 3);
System.out.println("使用rotate右移3位後:" + list);
Collections.rotate(list, -3);
System.out.println("使用rotate左移3位後:" + list);
Collections.rotate(list, 13);
System.out.println("使用rotate右移13位後:" + list);
}
輸出結果
未使用rotate前:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
使用rotate右移3位後:[7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
使用rotate左移3位後:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
使用rotate右移13位後:[7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
源碼分析
public static void rotate(List<?> list, int distance) {
// private static final int ROTATE_THRESHOLD = 100;
// 如果該list實現了RandomAccess接口,或者該list的大小小於100
if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
rotate1(list, distance);
else
rotate2(list, distance);
}
private static <T> void rotate1(List<T> list, int distance) {
// 得到list的大小
int size = list.size();
// 大小爲0直接返回
if (size == 0)
return;
// 對distance取餘,減少旋轉次數
distance = distance % size;
// 如果distance小於0,加上size,使distance落在[0,size)上
if (distance < 0)
distance += size;
// distance爲0沒有旋轉的必要,直接返回
if (distance == 0)
return;
for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
// 拿到cycleStart位置的值
T displaced = list.get(cycleStart);
// 存下cycleStart
int i = cycleStart;
// 直接將數放到最終位置
do {
// 找到cycleStart旋轉後的落腳點
i += distance;
// 如果超過列表大小,減回來,使i落在[0,size)中
if (i >= size)
i -= size;
// 在新位置賦值原來cycleStart位置的值,並拿到舊值
displaced = list.set(i, displaced);
nMoved ++;
} while (i != cycleStart);
}
}
private static void rotate2(List<?> list, int distance) {
// 得到list的大小
int size = list.size();
// 大小爲0沒有翻轉的必要
if (size == 0)
return;
// distance 是需要從列表後面移到列表前的數的個數
// mid 計算的是移動後依然還處於列表後面的數
// ex:1 2 3 4 5,distance = 2
// mid 是指 1 2 3,這 3 個數未被重新移動到列表開頭
int mid = -distance % size;
if (mid < 0)
mid += size;
if (mid == 0)
return;
// 通過mid進行劃分,根據線性代數原理
// ((AB)^T)^T = AB = (B^TA^T)^T
// 逆轉 [0,mid)
reverse(list.subList(0, mid));
// 逆轉 [mid,size)
reverse(list.subList(mid, size));
// 逆轉整個列表
reverse(list);
}
13. indexOfSubList
返回目標列表在指定列表第一次出現的起始位置,如果未找到,返回 -1
聲明
public static int indexOfSubList(List<?> source, List<?> target)
參數
- source:搜索target第一次出現的列表
- target:要在source中作爲子列表搜索的列表
返回值
返回target在source中首次出現的下標,如果target未找到,返回-1
異常
無
使用示例
代碼
public void indexOfSubListTest() {
List<Integer> source = new ArrayList<>();
for (int i = 0; i < 10; i++) {
source.add(i);
}
source.add(2);
source.add(3);
List<Integer> target = new ArrayList<>();
target.add(2);
target.add(3);
System.out.println("target在srouce中第一次出現:" + Collections.indexOfSubList(source, target));
target.add(6);
System.out.println("target在source未出現:" + Collections.indexOfSubList(source, target));
}
輸出結果
目標list在srouce中第一次出現:2
如果目標list在source未出現:-1
源碼分析
public static int indexOfSubList(List<?> source, List<?> target) {
int sourceSize = source.size();
int targetSize = target.size();
// 最大需要比較的長度
int maxCandidate = sourceSize - targetSize;
// private static final int INDEXOFSUBLIST_THRESHOLD = 35;
// 如果 source的大小大於35,或者source和target都實現了RandomAccess接口
if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
(source instanceof RandomAccess&&target instanceof RandomAccess)) {
// 標籤
nextCand:
// candidate 從 0 開始
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
for (int i=0, j=candidate; i<targetSize; i++, j++)
// 如果 target.get(i)和source.get(j)不相等,結束此次以ij爲變量的循環
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:
// candidate 從 0 開始
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;
}
}
// 未找到,返回 -1
return -1; // No candidate matched the target
}
static boolean eq(Object o1, Object o2) {
return o1==null ? o2==null : o1.equals(o2);
}
14. lastIndexOfSubList
返回目標列表在指定列表最後一次出現的起始位置,如果未找到,返回 -1
聲明
public static int lastIndexOfSubList(List<?> source, List<?> target)
參數
- source:搜索target最後一次出現的列表
- target:要在source中作爲子列表搜索的列表
返回值
返回target在source中最後一次出現的下標,如果target未找到,返回-1
異常
無
使用示例
代碼
public void lastIndexOfSubListTest() {
List<Integer> source = new ArrayList<>();
for (int i = 0; i < 10; i++) {
source.add(i);
}
source.add(2);
source.add(3);
List<Integer> target = new ArrayList<>();
target.add(2);
target.add(3);
System.out.println("target在srouce中最後一次出現:" + Collections.lastIndexOfSubList(source, target));
target.add(6);
System.out.println("target在source未出現:" + Collections.lastIndexOfSubList(source, target));
}
輸出結果
target在srouce中最後一次出現:10
target在source未出現:-1
源碼分析
public static int lastIndexOfSubList(List<?> source, List<?> target) {
int sourceSize = source.size();
int targetSize = target.size();
// 最大需要比較的長度
int maxCandidate = sourceSize - targetSize;
// private static final int INDEXOFSUBLIST_THRESHOLD = 35;
// source大小小於35,或者source實現了RandomAccess接口
if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
source instanceof RandomAccess) { // Index access version
// 標籤
nextCand:
// candidate 從最大需要比較的長度maxCandidate開始
for (int candidate = maxCandidate; candidate >= 0; candidate--) {
for (int i=0, j=candidate; i<targetSize; i++, j++)
// 如果target.get(i)和source.get(j)不等,該ij循環結束,繼續下一輪candidate循環
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
// sourceSize<targetSize,肯定找不到,直接返回-1
if (maxCandidate < 0)
return -1;
// 使用迭代器指向maxCandidate位置
ListIterator<?> si = source.listIterator(maxCandidate);
nextCand:
// candidate從maxCandidate開始
for (int candidate = maxCandidate; candidate >= 0; candidate--) {
ListIterator<?> ti = target.listIterator();
for (int i=0; i<targetSize; i++) {
// 如果不等,退出此輪i循環,且迭代器回退
if (!eq(ti.next(), si.next())) {
if (candidate != 0) {
// Back up source iterator to next candidate
for (int j=0; j<=i+1; j++)
si.previous();
}
continue nextCand;
}
}
return candidate;
}
}
// 沒找到返回-1
return -1; // No candidate matched the target
}
// 和 indexOfSubList用的同一個eq方法
static boolean eq(Object o1, Object o2) {
return o1==null ? o2==null : o1.equals(o2);
}
15. nCopies
返回 n 個指定對象的副本組成的不可變列表
聲明
public static <T> List<T> nCopies(int n, T o)
參數
- n:返回列表中元素的個數
- o:返回列表中重複出現的元素
返回值
由 n 個 o 組成的不可變列表
異常
-
IllegalArgumentException:如果 n < 0
// 拋出IllegalArgumentException異常 Collections.nCopies(-2,1);
使用示例
代碼
public void nCopiesTest(){
List<String> list1 = Collections.nCopies(4, "hhhh");
System.out.println("list1得到的是:" + list1);
List<Integer> list2 = Collections.nCopies(3, 2);
System.out.println("list2得到的是:" + list2);
}
輸出結果
list1得到的是:[hhhh, hhhh, hhhh, hhhh]
list2得到的是:[2, 2, 2]
源碼分析
public static <T> List<T> nCopies(int n, T o) {
// n<0拋出異常
if (n < 0)
throw new IllegalArgumentException("List length = " + n);
// 創建一個靜態內部類
return new CopiesList<>(n, o);
}
private static class CopiesList<E> extends AbstractList<E> implements RandomAccess, Serializable{
private static final long serialVersionUID = 2739099268398711800L;
// 該類的兩個成員變量都被 final 修飾
final int n;
final E element;
// 構造方法中已經初始化兩個成員變量
// 所以該類的 n 和 element已不可變
CopiesList(int n, E e) {
assert n >= 0;
this.n = n;
element = e;
}
public int size() {
return n;
}
public boolean contains(Object obj) {
return n != 0 && eq(obj, element);
}
public int indexOf(Object o) {
return contains(o) ? 0 : -1;
}
public int lastIndexOf(Object o) {
return contains(o) ? n - 1 : -1;
}
public E get(int index) {
if (index < 0 || index >= n)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+n);
return element;
}
public Object[] toArray() {
final Object[] a = new Object[n];
if (element != null)
Arrays.fill(a, 0, n, element);
return a;
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
final int n = this.n;
if (a.length < n) {
a = (T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), n);
if (element != null)
Arrays.fill(a, 0, n, element);
} else {
Arrays.fill(a, 0, n, element);
if (a.length > n)
a[n] = null;
}
return a;
}
public List<E> subList(int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > n)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
return new CopiesList<>(toIndex - fromIndex, element);
}
// Override default methods in Collection
@Override
public Stream<E> stream() {
return IntStream.range(0, n).mapToObj(i -> element);
}
@Override
public Stream<E> parallelStream() {
return IntStream.range(0, n).parallel().mapToObj(i -> element);
}
@Override
public Spliterator<E> spliterator() {
return stream().spliterator();
}
}
16. fill
將指定 list 的元素全部替換爲指定值
聲明
public static <T> void fill(List<? super T> list, T obj)
參數
- list:要進行元素替換的列表
- obj:用於填充指定值的元素
返回值
void
異常
-
UnsupportedOperationException:如果指定 list 或者其迭代器不支持 set 操作
List<Integer> list = Collections.nCopies(4,2); // 拋出UnsupportedOperationException異常,nCopies返回的是一個Collections類中的靜態內部類 // 該靜態內部類不存在set方法 Collections.fill(list,1);
代碼示例
代碼
public void fillTest() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.println("使用fill方法前:" + list);
Collections.fill(list, 1);
System.out.println("使用fill方法後:" + list);
}
輸出結果
使用fill方法前:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
使用fill方法後:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
源碼分析
public static <T> void fill(List<? super T> list, T obj) {
int size = list.size();
// private static final int FILL_THRESHOLD = 25;
// list的大小小於25或者該list實現了 RandomAccess 接口,使用for循環覆蓋
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);
}
}
}