Collections工具类

郎家岭伯爵 2023年01月29日 532次浏览

背景

Collections 工具类 JDK 提供的一个工具类,位于 java.util 包下,提供了一系列的静态方法,方便我们对集合进行各种操作,算是集合框架的一个大管家。

实现

排序操作

  • reverse(List list):反转顺序
  • shuffle(List list):洗牌,将顺序打乱
  • sort(List list):自然升序
  • sort(List list, Comparator c):按照自定义的比较器排序
  • swap(List list, int i, int j):将 i 和 j 位置的元素交换位置
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author 郎家岭伯爵
 * @time 2023/1/29 10:28
 */
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("langjialing0");
        list.add("langjialing1");
        list.add("langjialing2");
        list.add("langjialing3");
        list.add("langjialing4");

        System.out.println("原始顺序:" + list);

        // 反转
        Collections.reverse(list);
        System.out.println("使用Collections反转后:" + list);

        // 洗牌
        Collections.shuffle(list);
        System.out.println("使用Collections洗牌后:" + list);

        // 自然升序
        Collections.sort(list);
        System.out.println("使用Collections自然升序后:" + list);

        // 交换顺序
        Collections.swap(list, 1, 3);
        System.out.println("使用Collections交换顺序后:" + list);
    }
}

输出:

原始顺序:[langjialing0, langjialing1, langjialing2, langjialing3, langjialing4]
使用Collections反转后:[langjialing4, langjialing3, langjialing2, langjialing1, langjialing0]
使用Collections洗牌后:[langjialing3, langjialing1, langjialing0, langjialing2, langjialing4]
使用Collections自然升序后:[langjialing0, langjialing1, langjialing2, langjialing3, langjialing4]
使用Collections交换顺序后:[langjialing0, langjialing3, langjialing2, langjialing1, langjialing4]

查找操作

  • binarySearch(List list, Object key):二分查找法,前提是 List 已经排序过了
  • max(Collection coll):返回最大元素
  • max(Collection coll, Comparator comp):根据自定义比较器,返回最大元素
  • min(Collection coll):返回最小元素
  • min(Collection coll, Comparator comp):根据自定义比较器,返回最小元素
  • fill(List list, Object obj):使用指定对象填充
  • frequency(Collection c, Object o):返回指定对象出现的次数
// 最大元素
System.out.println("最大元素:" + Collections.max(list));

// 最小元素
System.out.println("最小元素:" + Collections.min(list));

// 元素出现的次数
System.out.println("元素出现的次数:" + Collections.frequency(list, "langjialing0"));

// 二分查找:没有经过排序的二分查找的元素是不确定的
Collections.shuffle(list);
System.out.println("未经过排序的二分查找:" + Collections.binarySearch(list, "langjialing2"));

// 二分查找:经过排序后的二分查找的元素是一定的
Collections.sort(list);
System.out.println("经过排序后的二分查找:" + Collections.binarySearch(list, "langjialing2"));

// 填充
Collections.fill(list, "langjialing");
System.out.println("填充后:" + list);

输出:

最大元素:langjialing4
最小元素:langjialing0
元素出现的次数:1
未经过排序的二分查找:-4
经过排序后的二分查找:2
填充后:[langjialing, langjialing, langjialing, langjialing, langjialing]

同步控制

例如 HashMap、ArrayList 是线程不安全的,没法在多线程环境下使用, Collections 工具类中提供了多个 synchronizedXxx 方法,这些方法会返回一个同步的对象,从而解决多线程中访问集合时的安全问题。

使用起来很简单:

List<String> synchronizedList = Collections.synchronizedList(list);
    ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

既然封装类内部已经加了对象锁,为什么外部还要加一层对象锁?
看源码可知,Collections.synchronizedList 中很多方法,比如equals、hasCode、get、set、add、remove、indexOf、lastIndexOf……
都添加了锁,但是 List 中迭代器没有加锁:

Iterator<E> iterator();

因此,迭代器没有加锁,不是线程安全的,所以如果要遍历,还是必须要在外面加一层锁。

使用 Iterator 迭代器的话,似乎也没必要用 Collections.synchronizedList 的方法来包装了,因为反正都是必须要使用 Synchronized 代码块包起来的。

所以总的来说,Collections.synchronizedList 这种做法,适合不需要使用Iterator、对性能要求也不高的场景。

其它操作

  • addAll(Collection<? super T> c, T… elements):往集合中添加元素

  • disjoint(Collection c1, Collection c2):判断两个集合是否没有交集

disjoint 方法是判断是否没有交集,而非是否有交集。

// 向集合中添加元素
Collections.addAll(list, "郎家岭0", "郎家岭1", "郎家岭2");
System.out.println("addAll后:" + list);

// 判断集合是否没有交集
List<String> list1 = new ArrayList<>();
list1.add("langjialing");
list1.add("郎家岭0");
System.out.println("是否有交集:" + (Collections.disjoint(list, list1) ? "是":"否"));

输出:

addAll后:[langjialing, langjialing, langjialing, langjialing, langjialing, 郎家岭0, 郎家岭1, 郎家岭2]
是否有交集:否

总结

Collections 工具类常规使用。