在这里推荐一下韩顺平老师的 Java 系列教程,讲得真的非常细腻和详细。

一、集合体系图

2021-04-22_222213

二、Collection 接口及其常用方法

2.1、Collection 接口声明

image-20210422222457945

  • Collection 实现子类可以存放多个元素,每个元素可以是 Object
  • 有些 Collection 的实现类可以存放重复的元素,有些不可以
  • 有些 Collection 的实现类是有序的,有些不是有序的
  • Collection 接口没有直接的实现子类,但其子接口 SetList 有一系列实现类

2.2、Collection 常用方法

1、方法一览

image-20210422222816057

2、add(E)

用于添加单个元素

3、remove(Object)

用于删除指定元素

4、contains(Object)

判断元素是否存在

5、size()

获取集合中元素个数

6、isEmpty()

判断集合是否为空

7、clear()

清空集合对象

8、addAll(Collection<? extends E>)

添加多个元素

9、containsAll(Collection<?>)

判断多个元素是否都存在

10、removeAll(Collection<?>)

移除多个元素

11、retainAll(Collection<?>)

用于保留两个集合对象中都有的元素。

2.3、迭代器遍历

1、Iterator 接口及 iterator 方法

Collection 集合中有一个 iterator 方法,这个方法用于返回一个 Iterator 对象

image-20210422223849062

  • IteratorCollection 接口的父接口,用于遍历 Collection 集合中的元素。
  • 所有实现了 Collection 接口的集合类都有一个 iterator 方法,用于返回一个迭代器
  • Iterator 仅用于遍历集合,本身不存放对象。

迭代器的执行原理

  • 使用 Iterator iterator = coll.iterator() 获取集合对象 coll 的迭代器。
  • 使用 hasNext() 判断是否还有下一个元素
  • next() 方法的作用有:
    • 指针下移
    • 将下移后指针位置上的元素返回

迭代器一开始的指针指向第一个元素前一格。

2、Collection 接口遍历元素方式一 - 使用 Iterator

  • 创建一个 ArrayList 对象,然后使用迭代器进行遍历
1
2
3
4
5
6
7
8
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add("string" + i);
}
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}

结果

image-20210422224816360

3、注意

在调用 iterator.next() 方法前必须使用 iterator.hasNext() 方法进行检测。

若不调用,且下一条记录无效,此时直接调用 iterator.next() 会直接抛出 NoSuchElementException 异常。

如果希望再次遍历,那么需要重置迭代器,使用以下的代码重置迭代器

1
iterator = list.iterator();

4、Collection 接口遍历元素方式二 - 使用增强 for 循环

1
2
3
4
5
6
7
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add("string" + i);
}
for (String s : list) {
System.out.println(s);
}

增强 for 循环底层仍然使用了迭代器

5、Collection 接口遍历元素方式三 - 使用 stream 流

  • 方法一
1
list.forEach(System.out::println);
  • 方法二
1
list.stream().forEach(System.out::println);

三、List

3.1、概述

1、基本介绍

List 接口是 Collection 接口的子接口

  • List 集合类中元素 有序 ,即添加顺序与取出顺序一致,且可以重复
  • List 集合中每个元素都有其对应的顺序索引,即支持索引
  • List 容器中的元素都对应一个整数型序号记载其在容器中的为止,可以根据序号存取容器中的元素
  • ArrayList 允许加入多个 null
  • JDK API 中 List 接口的常用实现类有
    • ArrayList
    • LinkedList
    • Vector

2、方法一览

image-20210422231600456

3.2、方法介绍

1、void add(int index, E element)

在 index 位置插入元素 element

2、boolean addAll(int index, Collection<? extends E> coll)

从 index 位置开始,将 coll 集合中的元素加入到该集合中

3、Object get(int index)

获取指定 index 位置的元素

4、int indexOf(E ele)

返回 ele 在集合中首次出现的位置

5、int lastIndexOf(E ele)

返回 ele 在集合中最后一次出现的位置

6、E remove(int index)

移除并返回指定位置的元素

7、E set(int index, E ele)

将 index 位置的元素设置为 ele ,相当于替换

8、List subList(int fromIndex, int toIndex)

返回从 fromIndextoIndex 间的子集合

3.3、ArrayList 源码分析

1、底层存储结构

ArrayList 底层维护了一个 Object 类型的数组 elementDataArrayList 底层存储结构为 动态数组

image-20210423184454292

2、构造函数

ArrayList 中存在三个构造函数,分别为无参构造函数、给定初始容量的构造函数和给定集合的构造函数。

image-20210423184653176

  • 无参构造函数

使用无参构造函数构造 ArrayList 对象时,会构造一个空数组

1
2
3
4
5
6
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

DEFAULTCAPACITY_EMPTY_ELEMENTDATA

1
2
3
4
5
6
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • 传入初始容量的构造函数
  1. 对用户传入的初始容量 initialCapacity 进行判断,若传入参数大于0,则直接开辟一个长度为 initialCapacity 的 Object 数组
  2. 如果用户传入的初始容量为 0 ,那么直接初始化数组为一个空数组 {}
  3. 如果用户传入的初始容量小于0,则抛出一个参数不合法异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
  • 传入集合对象的构造函数
  1. 将传入的集合转换为一个数组,然后赋给当前 ArrayList 的底层数组
  2. 对数组长度进行判断,如果长度不为0,那么使用 Arrays 工具类拷贝数组
  3. 如果数组长度为0,那么直接初始化数组为空数组 {}
1
2
3
4
5
6
7
8
9
10
11
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
  • EMPTY_ELEMENTDATA
1
2
3
4
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};

3、add 方法

如果用户使用无参构造器构造 ArrayList 对象,那么会初始化底层数组 elementData 为一个空数组,在第一次往 ArrayList 对象中添加数组时,会扩容 elementData 长度为10,以后的扩容中,会扩容 elementData 长度为 1.5 倍

1
2
3
4
5
6
7
8
9
10
11
12
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;

if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}

ArrayList 使用位运算获取扩容大小

image-20210423191358644

  • 在添加元素前,先调用 ensureCapacityInternal 方法确认添加后的容量够不够
1
2
3
4
5
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
  • ensureCapacityInternal 方法内部调用了 ensureCapacityInternal 方法
1
2
3
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
  • ensureExplicitCapacity 方法中,判断添加后的 size 是否大于当前 ArrayList 底层数组 elementData 长度,如果大于,那么调用 grow 方法进行扩容。
1
2
3
4
5
6
7
private void ensureExplicitCapacity(int minCapacity) {
modCount++;

// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
  • 在确保数组容量足够后,在将待添加元素放在数组最后一个位置,同时令当前数组元素个数 size+1,然后返回 true

  • rangeCheck

该方法用于判断数组下标是否越界

1
2
3
4
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

3.4、Vector

1、介绍

Vector 也是 List 接口的一个实现子类,它继承自 AbstractList ,实现了 List 接口

image-20210423195354112

Vector 底层也是一个对象数组,由于 Vector 类的操作方法都带有 synchronized,所以它是线程安全的,但开发中多线程情况下不推荐使用 Vector,使用 CopyOnWriteArrayList

  • 底层数组

image-20210423195524616

  • 操作方法(局部)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}

public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}

public synchronized void removeAllElements() {
modCount++;
// Let gc do its work
for (int i = 0; i < elementCount; i++)
elementData[i] = null;

elementCount = 0;
}

2、构造函数

  • 无参构造函数

如果调用无参构造函数,那么默认构造大小为 10 的数组,同时扩容按两倍扩容

image-20210423200355210

3.5、LinkedList

1、介绍

  • LinkedList 底层实现了双向链表双端队列特点
  • 可以添加任意元素,且元素可以重复
  • 线程不安全,没有实现同步

2、底层结构

  • LinkedList 底层维护了一个双向链表
  • LinkedList 中维护了两个属性 first 和 last 分别指向首节点和尾节点
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;

/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
  • 每个节点中又维护了 prevnextitem 三个属性,其中通过 prev 指向前一个节点,next 指向后一个节点。
1
2
3
4
5
6
7
8
9
10
11
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;

Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
  • 所以 LinkedList 中元素的添加和删除不是通过数组完成的,相对来说效率较高

3、addFirst(E e)

将传入元素 e 置为当前双向链表的头元素

1
2
3
public void addFirst(E e) {
linkFirst(e);
}

查看 linkFirst 方法

1
2
3
4
5
6
7
8
9
10
11
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
  1. 将当前链表的首元素置为变量 f
  2. 然后以传入的元素 e 构造一个 Node 节点对象,其中新节点的前指针为 null,后指针为原来链表的首元素 f
  3. 如果 f 为空,证明原来的链表为空,此时直接将最后一个元素 last 置为新节点即可
  4. 否则就令 f 的前驱指针指向新节点,然后令元素个数和修改次数都+1,并退出方法

3.6、List 集合选择

1、ArrayListLinkedList 比较

底层结构增删效率改查效率
ArrayList
LinkedList

如何选择ArrayListLinkedList

  1. 如果改查操作多,那么选择ArrayList
  2. 如果增删操作多,那么选择 LinkedList
  3. 一般来说,在程序中查询较多,因此大部分情况下使用ArrayList

四、Set

4.1、概述

  • 无序(添加和取出的顺序不一致),没有索引
  • 不允许重复元素,最多包含一个 null
  • JDK API 中 Set 接口重要的实现类有:
    • HashSet
    • TreeSet

和 List 接口一样,Set 接口也是 Collection 接口的子接口,所以常用方法和 Collection 接口一样。Set 接口同样可以使用迭代器或者增强 for 循环遍历,但不能使用索引方式获取

4.2、HashSet

HashSet 实现了 Set 接口,底层是一个 HashMap,可以存放 null,但只能存放一个 null,不能有重复的元素/对象,在多线程高并发条件下应该使用 CopyOnWriteArraySet

4.3、TreeSet

1、介绍

TreeSet 是一个有序的集合,它的作用是提供有序的Set集合。它继承了 AbstractSet 抽象类,实现了 NavigableSet<E>CloneableSerializable 接口。TreeSet 是基于 TreeMap 实现的,TreeSet 的元素支持2种排序方式:自然排序或者根据提供的 Comparator 进行排序。

如果使用 TreeSet 存储自定义的类,那么可以通过两个方法来构造排序规则

  • 自然排序
  1. 令我们自定义的类实现 Comparable 接口,然后覆写 compareTo 方法,这个方法接收一个 Object 对象,我们需要在该方法中先将传入的 Object 对象强转为我们自定义类的对象,然后自定义比较大小规则
1
2
3
4
5
6
7
8
9
10
11
12
13
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Comparable {
private Integer score;
private String name;

@Override
public int compareTo(Object o) {
Student student = (Student)o;
return this.score - student.score;
}
}
  1. 这个时候我们可以在 TreeSet 对象中添加此类对象
1
2
3
4
5
6
7
8
9
10
11
TreeSet<Student> students = new TreeSet<>();
Student student1 = new Student(99,"芜湖1");
Student student2 = new Student(13,"芜湖2");
Student student3 = new Student(22,"芜湖3");
Student student4 = new Student(31,"芜湖4");
Student student5 = new Student(44,"芜湖5");
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
students.add(student5);
  1. 查看结果,可以看到根据我们的自定义规则,即按成绩大小排序了
1
2
System.out.println("TreeSet中的情况为:");
students.forEach(System.out::println);

image-20210423224653601

  • 在构造 TreeSet 对象时传入一个 Comparator 比较器对象,自定义比较大小规则,可以使用 Lambda 表达式,这里仍然使用成绩比较学生优先级
  1. 使用和前面相反的排序规则
1
TreeSet<Student> students = new TreeSet<>((s1,s2) -> s2.getScore() - s1.getScore());
  1. 添加学生对象
1
2
3
4
5
6
7
8
9
10
Student student1 = new Student(99,"芜湖1");
Student student2 = new Student(13,"芜湖2");
Student student3 = new Student(22,"芜湖3");
Student student4 = new Student(31,"芜湖4");
Student student5 = new Student(44,"芜湖5");
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
students.add(student5);
  1. 去除 Student 实体类关于 Comparable 接口的相关信息

  2. 遍历,查看结果

image-20210423225306549

2、注意

当我们使用自定义类作为 TreeSet 的泛型时,我们必须保证我们自定义的类实现了 Comparable 方法,或者在 TreeSet 构造函数中传入一个 Comparator 实现类,否则会报 ClassCastException 异常

image-20210423225656867

五、Map

5.1、概述

  1. Collection 和 Map 并列存在,用于保存具有映射关系的数据,即Key-Value键值对
  2. Map 中的 Key 和 Value 可以是任意引用类型的数据。
  3. Map 中的 Key 不可以重复,而 Value 可以重复
  4. 常用 String 对象作为 Map 中的 Key
  5. Key 和 Value 之间存在一个单向一对一关系,通过指定 Key 总能找到对应 Value

5.2、Map 常用方法

1、put

添加键值对

2、remove

根据键删除键值对映射关系

3、get

根据键获取值

4、size

获取键值对个数

5、isEmpty

判断元素个数是否为0

6、clear

清空 Map 对象

7、containsKey

判断键是否存在

8、entrySet

获取所有关系:K-V

9、values

获取所有的值

10、keySet

获取所有键

5.3、Map 接口的遍历方法

1、准备数据

1
2
3
4
5
6
7
8
9
10
11
12
Map<String, String> map = new HashMap<>();
map.put("1","刘备");
map.put("2","诸葛亮");
map.put("3","关羽");
map.put("4","张飞");
map.put("5","赵云");
map.put("6","徐庶");
map.put("7","庞统");
map.put("8","黄忠");
map.put("9","魏延");
map.put("10","法正");
map.put("11","马超");

2、先取出所有 Key ,然后通过 Key 取出对应 Value

1
2
3
4
5
//1 先取出所有key,然后通过key获取value
Set<String> keySet = map.keySet();
keySet.forEach(key -> {
System.out.println("key:" + key + "-->value:" + map.get(key));
});

结果

image-20210423211940545

3、获取 Entry 集合,然后遍历 Entry 集合,逐个取出 Entry 对象的键和值

1
2
3
4
5
//2 获取entrySet,然后遍历 Entry 集合,逐个取出 Entry 对象的键和值
Set<Map.Entry<String, String>> entrySet = map.entrySet();
entrySet.forEach(entry -> {
System.out.println("key:" + entry.getKey() + "-->value:" + entry.getValue());
});

结果

image-20210423212437729

4、使用迭代器遍历 map 集合的 keySet,然后根据键获取值

1
2
3
4
5
6
7
8
//3 迭代器
System.out.println("------------------使用迭代器遍历keySet获取键值对信息---------------");
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while(iterator.hasNext()) {
String key = iterator.next();
System.out.println("key:" + key + "-->value:" + map.get(key));
}

结果

image-20210423213158379

5、使用迭代器遍历 map 集合的 entrySet,然后输出键值对信息

1
2
3
4
5
6
7
8
9
    //4 迭代器 + entrySet
System.out.println("使用迭代器遍历 map 集合的 entrySet ,然后输出键值对信息");
Set<Map.Entry<String, String>> entries = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while(iterator.hasNext()) {
Map.Entry entry = iterator.next();
System.out.println("key:" + entry.getKey() + "-->value:" + entry.getValue());
}
}

结果

image-20210423213714422

6、直接获取值集合

1
2
3
4
//5 通过values获取值集合
System.out.println("通过values获取值集合");
Collection<String> values = map.values();
values.forEach(System.out::println);

结果

image-20210423213915241

5.4、Map 实现类 - Properties

1、基本介绍

  1. Properties 类继承自 HashTable 类并实现了 Map 接口,也是使用一种键值对的形式保存数据
  2. Properties 还可以用于从 xxx.properties 配置文件中加载数据到 Properties 类对象,并进行读取和修改

2、常用方法

  • setProperty

添加/修改配置

1
2
3
4
5
6
7
8
9
Properties properties = new Properties();
//1 增
properties.setProperty("driver","com.mysql.jdbc.Driver");
properties.setProperty("url","jdbc:mysql://localhost:3306/test");
properties.setProperty("username","root");
properties.setProperty("password","root");
System.out.println("遍历Properties对象");
Set<Object> keySet = properties.keySet();
keySet.forEach(key -> System.out.println("key:" + (String)key + "--> value:" + properties.getProperty((String)key)));

结果如下:

image-20210423221400695

修改配置

1
2
3
//2 修改
properties.setProperty("password","123");
System.out.println("修改后password的值为:" + properties.getProperty("password"));

结果

image-20210423221728857

  • remove

移除配置

1
properties.remove("password");

image-20210423221956459

  • getProperty

获取配置信息

3、使用

使用 Properties 类获取配置文件中的配置

  • 在项目文件夹下创建一个 db.properties 配置文件
1
2
3
4
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&nullCatalogMeansCurrent=true&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=tianxin1230.
  • 创建一个文件输入流,指定读入的文件路径
  • 使用 Properties 的 load 方法读取文件输入流的配置信息
1
2
3
4
5
6
7
8
9
10
11
12
Properties properties = new Properties();
File file = new File("db.properties");
try {
InputStream inputStream = new FileInputStream(file);
properties.load(inputStream);
Set<Object> keySet = properties.keySet();
keySet.forEach(key -> System.out.println("key:" + (String)key + "--> value:" + properties.getProperty((String)key)));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

查看结果

image-20210423222810095

5.5、TreeMap

1、介绍

HashMapHashSet 的关系一样, TreeSet 底层同样是 TreeMap

image-20210423225932160

add 方法,可以看到每次添加的值同样是一个 静态常量 PRESENT

image-20210423230018440

静态常量定义如下

image-20210423230029665

2、使用

TreeSet 一样,TreeMap 同样有一个接收 Comparator 实现类的构造函数,在使用自定义类作为 TreeMap 的键时,我们可以令自定义类实现 Comparable 接口,或在构造 TreeMap 时传入一个 Comparator 实现类.

六、Collections 工具类

6.1、Collections 工具类介绍

  • Collections 工具类是一个操作 SetListMap 等集合的工具类。
  • Collections 提供了一系列静态方法对集合进行排序、查询和修改等操作。
  • 以下方法均为 static 静态方法

1、reverse(List)

反转 List 中元素的顺序

2、shuffle(List)

对 List 集合中的元素进行随机排序

3、sort(List)

根据元素自然顺序对指定 List 集合中的元素进行 升序排序

4、sort(List, Comparator)

根据指定的 Comparator 产生的顺序对指定 List 集合中的元素进行 升序排序

5、swap(List, int, int)

对指定 List 集合中的 i 处元素和 j 处元素进行交换,两个下标需要合理

6、synchronizedCollection(Collection)

将线程不安全的集合对象转换为线程安全的集合对象,synchronizedListsynchronizedSetsynchronizedMap 分别接收线程不安全的 List 、 Set 和 Map 实现类,然后返回一个线程安全的集合类(不推荐)

6.2、查找、替换

1、Object max/min(Collection)

按照元素的自然顺序,返回给定集合中的最大/小元素

2、Object max/min(Collection, Comparator)

按照比较器指定的顺序,返回给定集合中的最大/小元素

3、int frequency(Collection,Object)

返回指定集合中指定元素的出现次数

4、void copy(List dest,List src)

src 中的内容复制到 dest

5、boolean replaceAll(List list, Object oldVal, Object newVal)

用新值替换 List 对象中的旧值

6.3、Apache CollectionUtils

1、介绍

这里讲的 CollectionUtils 是在 apache 下,而不是 spring 下的集合工具类,它可以让代码更加简洁和安全,在 MAVEN 中的坐标为:

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>

image-20210423232505740

2、常用方法

  • CollectionUtils.addIgnoreNull(personList,null);

除非元素为null,否则向集合添加元素

  • CollectionUtils.collate(Iterable<? extends O> a, Iterable<? extends O> b)

将两个已排序的集合a和b合并为一个已排序的列表,以便保留元素的自然顺序

  • CollectionUtils.collate(Iterable<? extends O> a, Iterable<? extends O> b, Comparator<? super O> c)

将两个已排序的集合a和b合并到一个已排序的列表中,以便保留根据Comparator c的元素顺序。

  • CollectionUtils.containsAny(Collection<?> coll1, T... coll2)

返回该个集合中是否含有至少有一个元素

  • CollectionUtils.emptyIfNull(Collection<T> collection)

如果参数是null,则返回不可变的空集合,否则返回参数本身。

  • CollectionUtils.isEmpty(Collection<?> coll)

安全检查指定的集合是否为空

  • CollectionUtils.isNotEmpty(Collection<?> coll)

安全检查指定的集合是否不为空。

  • CollectionUtils.reverseArray(Object[] array)

反转给定数组的顺序。

  • CollectionUtils.subtract(Iterable<? extends O> a, Iterable<? extends O> b)

差集

  • CollectionUtils.union(Iterable<? extends O> a, Iterable<? extends O> b)

并集

  • CollectionUtils.intersection(Collection a, Collection b)

交集

  • boolean isEqualCollection(Collection a, Collection b)

判断两个集合是否相等