Java中的集合就像一个容器,专门用来存储Java对象。集合对象可以是任意的数据类型,并且长度可变。其中,这些集合类都位于java.util
包中,在使用时一定要注意导包的问题。
还记得我们在《Java讲课笔记08:数组》里讲利用Arrays类的sort()方法对数组进行降序排列的案例Example810吧。
这个案例使用集合类Collections的reverseOrder()方法作为Arrays类的sort()方法的第二个参数,用于实现对数组的降序排列。大家可以看看程序开头,就有导包的语句:
说明:虚线框里填写的都是接口类型,实线框里填写的都是具体的实现类。
Collection是单列集合根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是List和Set。
方法声明 | 功能描述 |
---|---|
boolean add(Object o) | 向集合中添加一个元素 |
boolean addAll(Collection c) | 将指定集合c中的所有元素添加到该集合中 |
void clear() | 删除该集合中的所有元素 |
boolean remove(Object o) | 删除该集合中指定的元素 |
boolean removeAll(Collection c) | 删除该集合中包含指定集合c中的所有元素 |
boolean isEmpty() | 判断该集合是否为空 |
boolean contains(Object o) | 判断该集合中是否包含某个元素 |
boolean containsAll(Collection c) | 判断该集合中是否包含指定集合c中的所有元素 |
Iterator iterator() | 返回在该集合的元素上进行迭代的迭代器(Iterator),用于遍历该集合所有元素 |
int size() | 获取该集合元素个数 |
Stream stream() | 将集合源转换为有序元素的流对象(JDK 8新方法) |
List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。
方法声明 | 功能描述 |
---|---|
void add(int index,Object element) | 将元素element插入在List集合的指定索引位置 |
boolean addAll(int index,Collection c) | 将集合c包含的所有元素插入到List集合的指定索引位置 |
Object get(int index) | 返回集合索引index处的元素 |
Object remove(int index) | 删除index索引处的元素 |
Object set(int index, Object element) | 将索引index处元素替换成element元素,并将替换后的元素返回 |
int indexOf(Object o) | 返回对象o在List集合中首次出现的位置索引 |
int lastIndexOf(Object o) | 返回对象o在List集合中最后一次出现的位置索引 |
List subList(int fromIndex, int toIndex) | 返回从索引fromIndex(包括)到 toIndex(不包括)处所有元素集合组成的子集合 |
Object[] toArray() | 将集合元素转换为数组 |
default void sort(Comparator super E> c) | 根据指定的比较器规则对集合元素排序(JDK 8新方法) |
ArrayList是List接口的一个实现类,它是程序中最常见的一种集合,其内部的数据存储结构是数组形式。
LinkedList是List接口的另一个实现类,其内部包含有两个Node类型的first和last属性的双向循环链表结构。
Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:
ArrayList是List接口的一个实现类,它是程序中最常见的一种集合,其内部的数据存储结构是数组形式。
package net.hw.lesson21;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 功能:创建与操作城市数组列表
* 作者:华卫
* 日期:2020年05月22日
*/
public class Example2101 {
public static void main(String[] args) {
// 创建城市数组列表对象
ArrayList<String> cities = new ArrayList<>();
// 判断数组列表是否为空
System.out.println("cities.isEmpty() = " + cities.isEmpty());
// 向数组列表里添加元素
cities.add("北京");
cities.add("上海");
cities.add("深圳");
cities.add(2, "广州"); // 广州在列表第3个位置
cities.add("泸州");
// 输出整个数组列表
System.out.println("cities = " + cities);
// 获取数组列表的长度
System.out.println("cities.size() = " + cities.size());
// 遍历数组
// 1. 采用普通for循环反序遍历数组列表
System.out.print("采用普通for循环反序遍历:");
for (int i = cities.size() - 1; i >= 0; i--) {
System.out.print(cities.get(i) + " ");
}
System.out.println();
// 2. 采用增强for循环遍历数组列表
System.out.print("采用增强for循环遍历:");
for (String city : cities) {
System.out.print(city + " ");
}
System.out.println();
// 3. 采用Lambda表达式遍历数组列表
System.out.print("采用Lambda表达式遍历:");
cities.forEach(city -> System.out.print(city + " "));
System.out.println();
// 4. 采用迭代器遍历数组列表
System.out.print("采用迭代器遍历:");
Iterator<String> iterator = cities.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 修改指定元素,比如将第5个元素改成“南京”
cities.set(4, "南京");
// 输出整个数组列表
System.out.println("cities = " + cities);
// 查询元素
// 按元素查询
String city = "深圳";
int position = cities.indexOf(city);
if (position == -1) {
System.out.println(city + "不在列表" + cities + "里。");
} else {
System.out.println("cities.get(" + position + ") = " + city);
}
// 课堂练习:按下标查询
// 删除元素
// 1. 按元素删除
city = "深圳";
boolean isDeleted = cities.remove(city);
if (isDeleted) {
System.out.println(city + "已从列表中删除。");
System.out.println("结果列表:" + cities);
} else {
System.out.println(city + "不在列表" + cities + "里。");
}
// 2. 按下标删除
int index = 2;
String deletedCity = null;
try {
deletedCity = cities.remove(index);
System.out.println("下标为[" + index + "]的城市[" + deletedCity + "]已从列表中删除。");
System.out.println("结果列表:" + cities);
} catch (Exception e) {
System.out.println("下标[" + index + "]超出范围!无法删除对应元素。");
}
// 判断数组列表是否为空
System.out.println("cities.isEmpty() = " + cities.isEmpty());
}
}
ArrayList cities = new ArrayList<>();
表名数组列表里的每个元素都是字符串类型,这样可以杜绝安全隐患LinkedList是List接口的另一个实现类,其内部包含有两个Node类型的first和last属性的双向循环链表结构。
方法声明 | 功能描述 |
---|---|
void add(int index, E element) | 在此列表中指定的位置插入指定的元素。 |
void addFirst(Object o) | 将指定元素插入集合的开头 |
void addLast(Object o) | 将指定元素添加到集合的结尾 |
Object getFirst() | 返回集合的第一个元素 |
Object getLast() | 返回集合的最后一个元素 |
Object removeFirst() | 移除并返回集合的第一个元素 |
Object removeLast() | 移除并返回集合的最后一个元素 |
boolean offer(Object o) | 将指定元素添加到集合的结尾 |
boolean offerFirst(Object o) | 将指定元素添加到集合的开头 |
boolean offerLast(Object o) | 将指定元素添加到集合的结尾 |
Object peek() | 获取集合的第一个元素 |
Object peekFirst() | 获取集合的第一个元素 |
Object peekLast() | 获取集合的最后一个元素 |
Object poll() | 移除并返回集合的第一个元素 |
Object pollFirst() | 移除并返回集合的第一个元素 |
Object pollLast() | 移除并返回集合的最后一个元素 |
void push(Object o) | 将指定元素添加到集合的开头 |
Object pop() | 移除并返回集合的第一个元素 |
package net.hw.lesson21;
import java.util.Iterator;
import java.util.LinkedList;
/**
* 功能:创建与操作学生链表
* 作者:华卫
* 日期:2020年05月23日
*/
public class Example2102 {
public static void main(String[] args) {
// 创建学生链表对象
LinkedList<String> students = new LinkedList<>();
// 判断链表是否为空
System.out.println("students.isEmpty() = " + students.isEmpty());
// 添加五个元素
System.out.print("链表添加五个元素:");
students.add("李晓红");
students.add("吴文燕");
students.add("唐雨涵");
students.add("郑小翠");
students.add(2, "王晓刚");
// 输出整个列表
System.out.println(students);
// 在链表尾添加新元素
System.out.print("在链表尾添加新元素:");
students.offer("李克红");
students.offerLast("张晓琳");
System.out.println(students);
// 在链表头添加新元素
System.out.print("在链表头添加新元素:");
students.push("零零七");
System.out.println(students);
// 遍历链表
// 1. 采用普通for循环遍历链表
System.out.print("采用普通for循环遍历链表:");
for (int i = 0; i < students.size(); i++) {
System.out.print(students.get(i) + " ");
}
System.out.println();
// 2. 采用增强for循环遍历链表
System.out.print("采用增强for循环遍历链表:");
for (String student : students) {
System.out.print(student + " ");
}
System.out.println();
// 3. 采用Lambda表达式遍历链表
System.out.print("采用Lambda表达式遍历链表:");
students.forEach(student -> System.out.print(student + " "));
System.out.println();
// 4. 采用迭代器遍历链表
System.out.print("采用迭代器遍历链表:");
Iterator<String> iterator = students.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
// 获取元素
// 1. 通过下标获取元素
int index = 4;
try {
System.out.println("students.get(" + index + ") = " + students.get(index));
} catch (Exception e) {
System.out.println("下标[" + index + "]超出链表范围!");
}
// 2. 获取链表头元素
System.out.println("链表头元素:" + students.get(0));
System.out.println("链表头元素:" + students.getFirst());
System.out.println("链表头元素:" + students.peek());
System.out.println("链表头元素:" + students.peekFirst());
// 3. 获取链表尾元素
System.out.println("链表尾元素:" + students.get(students.size() - 1));
System.out.println("链表尾元素:" + students.getLast());
System.out.println("链表尾元素:" + students.peekLast());
// 修改元素
students.set(0, "王大毛");
System.out.println("结果链表:" + students);
// 删除元素
// 1. 按下标删除元素
index = 3;
try {
String deletedStudent = students.remove(index);
System.out.println("下标为[" + index + "]的学生[" + deletedStudent + "]已从链表中删除。");
System.out.println("结果链表:" + students);
} catch (Exception e) {
System.out.println("下标[" + index + "]不在链表范围!");
}
// 2. 按元素删除
String student = "王晓刚";
boolean isDeleted = students.remove(student);
if (isDeleted) {
System.out.println("学生[" + student + "]已从链表中删除。");
System.out.println("结果链表:" + students);
} else {
System.out.println("学生[" + student + "]不在链表里,无法删除!");
}
// 3. 删除链表头元素
System.out.println("删除链表头元素:");
students.remove(0);
System.out.println("结果链表:" + students);
students.pollFirst();
System.out.println("结果链表:" + students);
// 4. 删除链表尾元素
System.out.println("删除链表尾元素:");
students.pollLast();
System.out.println("结果链表:" + students);
// 5. 删除链表全部元素
students.clear();
System.out.println("结果链表:" + students);
}
}
Iterator接口是Java集合框架中的一员,主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。
package net.hw.lesson21;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 功能:利用迭代器遍历学生数组列表
* 作者:华卫
* 日期:2020年05月23日
*/
public class Example2103 {
public static void main(String[] args) {
// 创建学生数组列表
ArrayList<String> students = new ArrayList<>();
// 添加列表元素
students.add("李晓红");
students.add("郑晓彤");
students.add("邱子涵");
students.add("吴晓燕");
students.add("董文刚");
// 由列表获取迭代器
Iterator iterator = students.iterator();
// 利用迭代器遍历数组列表
while (iterator.hasNext()) { // 判断迭代器是否有下一个元素
// 获取迭代器下一个元素
Object object = iterator.next();
System.out.print(object + " ");
}
}
}
Iterator迭代器对集合中的元素进行迭代时,如果调用了集合对象的remove()方法删除元素,会抛出ConcurrentModificationException
(并发修改异常)。
package net.hw.lesson21;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 功能:演示并发修改异常
* 作者:华卫
* 日期:2020年05月23日
*/
public class Example2106 {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("李香兰");
names.add("陈慧娴");
names.add("童安格");
names.add("谭咏麟");
System.out.println("姓名列表:" + names);
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("童安格")) {
names.remove(name);
}
}
System.out.println("姓名列表:" + names);
}
}
foreach循环是一种更加简洁的for循环,也称增强for循环,用于遍历数组或集合中的元素。
for (容器中元素类型 临时变量 :容器变量) {
// 执行语句
}
比如:
for (Object obj : list) {
System.out.println(obj);
}
package net.hw.lesson21;
import java.util.ArrayList;
/**
* 功能:利用增强for循环遍历学生数组列表
* 作者:华卫
* 日期:2020年05月23日
*/
public class Example2104 {
public static void main(String[] args) {
// 创建学生数组列表
ArrayList<String> students = new ArrayList<>();
// 添加列表元素
students.add("李晓红");
students.add("郑晓彤");
students.add("邱子涵");
students.add("吴晓燕");
students.add("董文刚");
// 利用增强for循环遍历数组列表
for (String student : students) {
System.out.print(student + " ");
}
}
}
foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改。
package net.hw.lesson21;
import java.util.ArrayList;
/**
* 功能:增强for循环不能修改集合元素
* 作者:华卫
* 日期:2020年05月23日
*/
public class Example2105 {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("李香兰");
names.add("陈慧娴");
names.add("童安格");
names.add("谭咏麟");
System.out.println("姓名列表:" + names);
// 利用增强for循环遍历数组
for (String name : names) {
name = "萌萌哒";
}
System.out.println("增强for循环修改后的列表:" + names);
// 利用普通for循环遍历数组
for (int i = 0; i < names.size(); i++) {
names.set(i, "萌萌哒");
}
System.out.println("普通for循环修改后的列表:" + names);
}
}
name = "萌萌哒";
只是将临时变量name指向了一个新的字符串,这与列表中的元素没有一点关系,而在普通for循环里,可以通过索引来修改列表中指定元素的值。forEach(Consumer action)方法是JDK 8中新增的遍历集合元素的方法,根据Lambda表达式特性,该方法所需要的参数是一个函数式接口。比如list.forEach(obj -> System.out.println("迭代集合元素:" + obj));
package net.hw.lesson21;
import java.util.ArrayList;
/**
* 功能:演示forEach遍历集合
* 作者:华卫
* 日期:2020年05月24日
*/
public class Example2107 {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("李香兰");
names.add("陈慧娴");
names.add("童安格");
names.add("谭咏麟");
System.out.println("姓名列表:" + names);
// 使用JDK8新增的forEach(Consumer action)方法遍历集合
System.out.print("采用forEach方法遍历:");
names.forEach(name -> System.out.print(name + " "));
}
}
JDK 8中还针对Iterator迭代器对象提供了一个forEachRemaining(Consumer action)方法来进行遍历,该方法同样需要一个函数式接口。
Iterator it = list.iterator();
it.forEachRemaining(obj -> System.out.println("迭代集合元素:" + obj));
package net.hw.lesson21;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 功能:演示forEachRemaining遍历迭代器
* 作者:华卫
* 日期:2020年05月24日
*/
public class Example2108 {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("李香兰");
names.add("陈慧娴");
names.add("童安格");
names.add("谭咏麟");
System.out.println("姓名列表:" + names);
// 获取数组列表的迭代器
Iterator<String> iterator = names.iterator();
// 使用JDK8新增的forEachRemaining(Consumer action)方法遍历迭代器
System.out.print("采用forEachRemaining方法遍历:");
iterator.forEachRemaining(name -> System.out.print(name + " "));
}
}
遍历List集合有三种方法:
这三种方法,对于单例集合Collection都是有效的,比如下一讲我们要学习的Set集合,也可以用上述三种方法进行遍历。