Java源码分析之Collections类

概述

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);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值