本文纲要
1 ) 集合概述
- 集合与数组对比
- 集合体系结构
2 ) 单列集合 Collection 入门
-
Collection 常用方法
- 添加元素:
add - 删除元素:
remove - 条件删除:
removeIf - 清空集合:
clear - 判断存在:
contains - 判断为空:
isEmpty - 获取大小:
size
- 添加元素:
-
迭代器
Iterator- 迭代器基本使用
- 迭代器原理分析
- 迭代器删除方法
-
增强 for 循环
- 基本格式
- 注意点
-
集合练习:存储学生对象并遍历
3 ) 总结
集合概述
1 ) 集合与数组对比
在 Java 中,如果需要同时存储多个元素,可以使用数组或集合。它们的主要区别如下:
- 长度可变性:数组的长度是固定的,一旦定义就不能改变;集合的长度是可变的,可以根据需要自动扩容。
- 存储数据类型:数组既可以存储基本数据类型(如
int、double),也可以存储引用数据类型(如String、自定义对象);集合只能存储引用数据类型,不能直接存储基本数据类型。如果确实需要存储基本数据类型,则必须使用它们对应的包装类(例如int对应Integer)。
代码演示
项目结构如下:
mycollection/
└── src/
└── com/
└── wb/
└── mycollectiondemo1/
├── MyCollectonDemo1.java
├── MyCollectonDemo2.java
├── MyCollectonDemo3.java
├── MyCollectonDemo4.java
├── MyCollectonDemo5.java
├── MyCollectonDemo6.java
├── MyCollectonDemo7.java
├── MyCollectonDemo8.java
└── Student.java
下面通过 MyCollectonDemo1 类来对比数组和集合的存储能力:
package com.wb.mycollectiondemo1;
import java.util.ArrayList;
import java.util.Arrays;
public class MyCollectonDemo1 {
public static void main(String[] args) {
// 数组可以存储基本数据类型也可以存储引用数据类型
int[] arr1 = {1, 2, 3};
String[] arr2 = {"a", "b", "c"};
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
// 集合存储引用数据类型
ArrayList<String> list1 = new ArrayList<>();
list1.add("a");
list1.add("b");
list1.add("c");
System.out.println(list1);
// 集合不能直接存储基本数据类型,必须使用包装类
// ArrayList<int> list2 = new ArrayList<int>(); // 错误写法
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
System.out.println(list2);
}
}
运行结果:
[1, 2, 3]
[a, b, c]
[a, b, c]
[1, 2, 3]
小结
- 数组长度固定,集合长度可变。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型;存基本类型时需要包装类。
2 ) 集合体系结构
Java 中的集合分为两大派系:
- 单列集合:一次只存储一个元素,顶层接口为
Collection。 - 双列集合:一次存储一对元素(键值对),顶层接口为
Map。
单列集合又根据是否允许重复元素分为:
- List 集合:允许重复元素,常见实现类有
ArrayList、LinkedList。 - Set 集合:不允许重复元素,常见实现类有
HashSet、TreeSet。
双列集合 Map 的常见实现类有 HashMap、TreeMap。
集合体系结构可用下图表示:
后续学习将按照自上而下的顺序进行:先掌握顶层接口或父类中的共性方法,再了解子类特有的功能,这样可以更好地举一反三
单列集合 Collection 入门
1 ) Collection 常用方法
Collection 是单列集合的顶层接口,不能直接实例化,通常使用多态方式创建其实现类对象(如 ArrayList)。下面是 Collection 中需要掌握的常用方法。
添加元素:add(E e)
Collection<String> collection = new ArrayList<>();
collection.add("aaa");
collection.add("bbb");
collection.add("ccc");
collection.add("dddd");
System.out.println(collection);
删除元素:remove(Object o)
该方法返回 boolean 值,表示删除是否成功
private static void method1(Collection<String> collection) {
// boolean remove(Object o) 从集合中移除指定的元素
// 如果删除成功,返回 true;否则返回 false
boolean result1 = collection.remove("aaa");
boolean result2 = collection.remove("ddd");
System.out.println(result1); // true
System.out.println(result2); // false
System.out.println(collection); // [bbb, ccc, dddd]
}
条件删除:removeIf(Predicate filter)
该方法接收一个 Predicate 函数式接口,可以使用 Lambda 表达式写出删除条件。底层会遍历集合,将每个元素交给 Lambda 表达式判断,若返回 true 则删除该元素,false 则保留。
private static void method2(Collection<String> collection) {
// removeIf 底层会遍历集合,s 依次表示集合中的每一个元素
// 若 lambda 表达式返回 true,则删除该元素;若返回 false,则保留
collection.removeIf((String s) -> {
return s.length() == 3; // 删除长度为3的字符串
});
System.out.println(collection); // 删除 aaa, bbb, ccc 后,只剩下 dddd
}
Lambda 表达式的写法依据:removeIf 的参数类型为 Predicate<T>,该接口只有一个抽象方法 boolean test(T t),因此 Lambda 表达式中的参数类型与集合元素类型一致,方法体返回布尔值即可。
清空集合:clear()
private static void method3(Collection<String> collection) {
// void clear() 清空集合,将集合中所有元素全部删除
collection.clear();
System.out.println(collection); // []
}
判断存在:contains(Object o)
private static void method4(Collection<String> collection) {
// boolean contains(Object o) 判断集合中是否存在指定的元素
boolean result = collection.contains("a");
System.out.println(result); // false
boolean result2 = collection.contains("aaa");
System.out.println(result2); // true
}
判断为空:isEmpty()
private static void method5(Collection<String> collection) {
// boolean isEmpty() 判断集合是否为空
collection.clear();
boolean result = collection.isEmpty();
System.out.println(result); // true
}
获取大小:size()
private static void method6(Collection<String> collection) {
// int size() 返回集合中元素的个数
int size = collection.size();
System.out.println(size); // 此时集合有4个元素,输出4
}
2 ) 迭代器 Iterator
迭代器是集合特有的遍历方式,所有单列集合都可以通过迭代器遍历。
迭代器基本使用
获取迭代器对象:通过集合的 iterator() 方法,默认指向集合的 0 索引位置。
遍历时需要两个方法:
hasNext():判断当前位置是否有元素可以取出。next():取出当前位置的元素,并将迭代器向后移动一个位置。
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
// 1. 获取迭代器对象,默认指向 0 索引
Iterator<String> it = list.iterator();
// 2. 利用 hasNext 和 next 循环遍历
while (it.hasNext()) {
System.out.println(it.next());
}
如果直接多次调用 next() 而不判断,当没有元素时继续调用会抛出 NoSuchElementException 异常,因此必须搭配 hasNext() 使用。
迭代器原理分析
迭代器的底层原理可以概括为三个方法的协作:
iterator():创建迭代器对象,等效于一个指针,初始指向集合的 0 索引位置。hasNext():询问当前指针位置是否有元素,有则返回 true,没有则返回 false。next():完成两件事——获取当前指针位置的元素,然后将指针移动到下一个位置。
遍历过程可用流程图表示:
当指针移动到最后一个元素之后时,hasNext() 返回 false,循环结束,不会再调用 next(),避免了异常。
迭代器删除方法
在遍历过程中,如果需要对元素进行删除,推荐使用迭代器自身的 remove() 方法。
该方法不需要参数,会删除当前迭代器指向的元素。
示例:删除集合中所有值为 “b” 的元素。
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("b".equals(s)) {
it.remove(); // 删除当前迭代器指向的元素
}
}
System.out.println(list); // [a, c, d]
为什么不用普通 for 循环删除?
普通 for 循环在删除元素时,由于集合长度动态变化,容易漏删相邻的重复元素。例如:
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if ("b".equals(s)) {
list.remove(i);
}
}
当删除一个 “b” 后,后面的元素会整体前移,而循环的索引 i 会继续加 1,导致紧邻的第二个 “b” 被跳过。
若必须使用普通 for 循环,可以在删除后手动执行 i-- 来修正索引,但这种方式容易出错,不如迭代器简洁。
3 ) 增强 for 循环
增强 for 循环(foreach)是 JDK 5 引入的简化遍历语法,其底层同样基于迭代器,适用于所有实现了 Iterable 接口的类(单列集合的顶层接口 Collection 继承了 Iterable,因此所有单列集合都支持增强 for;双列集合 Map 不直接支持,但可通过其他方式间接使用)。
基本格式
for (元素类型 变量名 : 待遍历的集合或数组) {
// 在此使用变量名,它依次表示每一个元素
}
示例:
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
// 增强 for 遍历
for (String str : list) {
System.out.println(str);
}
格式注意点:
- 数据类型必须与集合或数组中元素的类型一致。
- 变量名仅是一个临时变量,在循环过程中依次代表每个元素。
- 冒号后面是待遍历的集合或数组。
注意点
- 在增强 for 中修改临时变量的值,不会影响集合中的元素。
- 因为临时变量仅仅是一个副本,修改它并不会改变集合本身。
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (String str : list) {
str = "q"; // 修改的是临时变量 str
System.out.println(str); // 输出 q q q q
}
System.out.println(list); // 依然是 [a, b, c, d]
此外,IDEA 等开发工具提供了快捷生成方式:输入 list.for 并回车,即可自动生成增强 for 循环模板。
遍历方式选择建议
- 普通 for 循环:需要操作索引时使用。
- 迭代器:遍历过程中需要删除元素时使用。
- 增强 for 循环:仅单纯遍历时使用,代码最简洁。
集合练习:存储学生对象并遍历
需求:创建一个 Collection 集合,存储三个学生对象,并分别使用迭代器和增强 for 循环进行遍历。
学生类 Student
public class Student {
private String name;
private int age;
public Student() { }
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// getter / setter 省略
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
ArrayList<Student> list = new ArrayList<>();
Student s1 = new Student("小皮同学", 23);
Student s2 = new Student("小路同学", 31);
Student s3 = new Student("小贾同学", 33);
list.add(s1);
list.add(s2);
list.add(s3);
// 迭代器遍历
Iterator<Student> it = list.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s);
}
System.out.println("-------------------------");
// 增强 for 遍历
for (Student student : list) {
System.out.println(student);
}
运行结果:
Student{name='小皮同学', age=23}
Student{name='小路同学', age=31}
Student{name='小贾同学', age=33}
Student{name='小皮同学', age=23}
Student{name='小路同学', age=31}
Student{name='小贾同学', age=33}
总结
本文从集合与数组的对比入手,介绍了 Java 集合的体系结构,并重点讲解了单列集合 Collection 的常用方法、迭代器遍历、增强 for 循环等内容。通过代码实例和原理分析,帮助读者快速掌握:
- 集合长度可变、只能存储引用类型的特点;
- 单列集合与双列集合的顶层接口;
add、remove、removeIf、clear、contains、isEmpty、size等方法的使用;- 迭代器的工作原理及删除操作的优势;
- 增强 for 循环的格式与注意事项。
后续文章将继续深入 List、Set、Map 及其实现类的具体用法,敬请期待
184

被折叠的 条评论
为什么被折叠?



