经过前面25天的学习,我们已经打下了Java的语言基础。
从今天起,我们进入一个全新的、至关重要的领域------Java集合框架。
一、什么是集合框架
在没有集合框架之前,如果你需要存储一组学生对象,你可能会使用数组。
但数组有一个致命的缺陷:长度一旦确定,就没办法改变了。
定义短了,可能不够用,定义长了,又可能造成资源浪费。
为了解决这类问题,Java提供了一套性能优良、使用方便的API,用来表示和操作对象的集合。
可以把它看成一个收纳万物的"工具箱",里面有各种各样的"容器"(比如列表、集合、队列、映射表等),可以高效地对数据进行增、删、改、查等操作。
为什么Java要给我们提供这些集合框架?
很多复杂的数据结构,你如链表、哈希表、红黑树等,Java集合框架已经帮我们实现好了,而且经过了一定的优化,不再需要我们从零开始实现这些结构,方便我们的使用。
这些数据结构是我们在日常开发中比较常使用的,集合框架都经过了精心设计和优化,通常情况下比我们自己去现写的要高效得多。
集合框架提供了一套标准化的接口,不管具体的实现是什么,或者发生什么变化,操作这些集合的方法都是一致的,我们在学习和使用的时候,成本都比较低。
二、Java集合框架图谱
Java集合框架主要由两个核心接口分支构成,它们是所有集合类的"老祖宗":
2.1 Collection
ArrayList

HashSet

PriorityQueue

上面的ArrayList、HashSet、PriorityQueue都实现了一个共同的接口Collection。
Collection是存放独立元素的集合的根接口。它的特点就是,容器里的每个位置只存放一个元素。
Collection有三个主要的子接口:List、Set、Queue。
List是一个有序的集合,允许存放重复的元素。你可以像操作数组一样通过索引来访问元素。(代表实现:ArrayList, LinkedList)
Set是一个不重复元素的集合。它不保证元素的顺序(某些实现类除外)。(代表实现:HashSet, TreeSet)
Queue是一个按特定规则(通常是先进先出FIFO)来处理元素的集合。(代表实现:LinkedList, PriorityQueue)
2.2 Map
HashMap

Map是存放键值对的集合的根接口。
Map里的每个元素都包含一个唯一的键(Key)和一个值(Value)。
它不继承自Collection接口,自成一派。(代表实现:HashMap, TreeMap)
三、Collection的核心能力
Collection接口定义了所有单元素集合都必须具备的通用方法。
掌握了它,你就掌握了操作List、Set、Queue的一半了。
一起简单的梳理下Collection中定义的属性和行为:
java
public interface Collection<E> extends Iterable<E> {
// 集合里装的元素个数
int size();
// 集合是不是空的
boolean isEmpty();
// 集合里是不是包含某个对象
boolean contains(Object o);
// 返回一个用来遍历集合的迭代器
Iterator<E> iterator();
// 把集合转换成一个Object数组
Object[] toArray();
// 把集合转换成一个指定类型的数组
<T> T[] toArray(T[] a);
// 添加一个元素到集合里
boolean add(E e);
// 从集合里移除一个元素
boolean remove(Object o);
// 把另一个集合的所有元素都添加到这个集合
boolean addAll(Collection<? extends E> c);
// 移除集合里也存在于另一个集合中的所有元素
boolean removeAll(Collection<?> c);
// 清空集合里的所有元素
void clear();
}
Collection里的E就是我们之前学习的泛型,表示元素的类型。
四、Iterable和Iterator
你可能已经注意到,Collection接口继承了一个Iterable接口。
Iterable接口其实是Java 5引入的,它让实现了这个接口的集合都具备了使用for-each循环的能力。
我们在看继承关系的时候,看到able结尾的接口,大多数情况下下就可以理解成,让子类具有某项能力。
java
public interface Iterable<E> {
Iterator<E> iterator();
}
Iterator(迭代器) 可以看成真正负责遍历的指针。
类似一个游标,在集合上移动,并提供了安全地访问和删除元素的方法。
java
public interface Iterator<E> {
// 判断集合里是不是还有下一个元素可以访问。
boolean hasNext();
// 返回集合里的下一个元素,并将"指针"后移一位。
E next();
}
提到删除元素,我们在初学的时候,还会遇到一个坑。
java
package com.lazy.snail.day26;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName Day26Demo
* @Description TODO
* @Author lazysnail
* @Date 2025/6/23 13:42
* @Version 1.0
*/
public class Day26Demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("懒惰");
list.add("蜗牛");
list.add("Java");
for (String str : list) {
if ("懒惰".equals(str)) {
list.remove(str);
}
}
}
}
在调用list.remove()的时候,ArrayList的内部结构发生了变化(元素数量、索引等),但迭代器Iterator并不知道这个变化。
当迭代器继续下一次next()操作时,它会发现"账对不上了",然后马上就抛出ConcurrentModificationException(并发修改异常)来防止后面可能发生更严重的数据错乱问题。
推荐的遍历删除方式就是使用迭代器的remove()方法:
java
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String str = iterator.next();
if ("懒惰".equals(str)) {
iterator.remove();
}
}
iterator.remove()会通知集合本次修改,确保数据的一致性,因此是唯一推荐在遍历时修改集合的方式。
在实际开发中,必须使用迭代器的remove()或removeIf来保证代码的健壮性和可维护性。
结语
今天,我们算是开始了一个Java新板块的学习。
我们了解了Java集合框架是什么、它的宏观架构,了解了根接口Collection所定义的通用能力。
然后聊了一下迭代器和ConcurrentModificationException。
接下来我们会看一下集合框架下的一些具体实现。
下一篇预告
Day27 | List接口详解
如果你觉得这系列文章对你有帮助,欢迎关注专栏,我们一起坚持下去!
更多文章请关注我的公众号《懒惰蜗牛工坊》