List集合因为支持索引,所以多了很多索引操作的独特API
,其他Collection的功能List也都能继承了。
方法 | 说明 |
---|---|
void add(int index, E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index, E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
package com.app.d5_collection_list;
import java.util.ArrayList;
import java.util.List;
/**
目标:掌握List集合特有的方法:API
*/
public class ListDemo1 {
public static void main(String[] args) {
// 1、创建一个ArrayList集合
// List: 有序、可重复、有索引
// 多态写法
List<String> list = new ArrayList<>();
list.add("《你好,李焕英》");
list.add("《喜羊羊与灰太狼》");
list.add("《神雕侠侣》");
list.add("《神雕侠侣》");
list.add("JavaSE基础");
list.add("JavaSE基础");
// 2、根据指定索引处插入指定的元素
list.add(5, "《三国演义》");
System.out.println(list); // [《你好,李焕英》, 《喜羊羊与灰太狼》, 《神雕侠侣》, 《神雕侠侣》, JavaSE基础, 《三国演义》, JavaSE基础]
System.out.println("-------------------------------------");
// 3、删除指定索引处的元素,返回被删除的元素
System.out.println("删除索引为4的元素:" + list.remove(4)); // JavaSE基础
System.out.println("删除索引为2的元素:" + list.remove(2)); // 《神雕侠侣》
System.out.println(list); // [《你好,李焕英》, 《喜羊羊与灰太狼》, 《神雕侠侣》, 《三国演义》, JavaSE基础]
System.out.println("-------------------------------------");
// 4、获取指定索引处的元素,返回被指定的元素
System.out.println("获取索引为0的元素:" + list.get(0)); // 《你好,李焕英》
System.out.println("获取索引为3的元素:" + list.get(3)); // 《三国演义》
System.out.println("-------------------------------------");
// 5、修改指定索引处的元素
System.out.println("修改索引为3的元素:" + list.set(4, "《射雕英雄传》"));
System.out.println(list); // [《你好,李焕英》, 《喜羊羊与灰太狼》, 《神雕侠侣》, 《三国演义》, 《射雕英雄传》]
}
}
[《你好,李焕英》, 《喜羊羊与灰太狼》, 《神雕侠侣》, 《神雕侠侣》, JavaSE基础, 《三国演义》, JavaSE基础]
-------------------------------------
删除索引为4的元素:JavaSE基础
删除索引为2的元素:《神雕侠侣》
[《你好,李焕英》, 《喜羊羊与灰太狼》, 《神雕侠侣》, 《三国演义》, JavaSE基础]
-------------------------------------
获取索引为0的元素:《你好,李焕英》
获取索引为3的元素:《三国演义》
-------------------------------------
修改索引为3的元素:JavaSE基础
[《你好,李焕英》, 《喜羊羊与灰太狼》, 《神雕侠侣》, 《三国演义》, 《射雕英雄传》]
Process finished with exit code 0
1、List系列集合的特点是什么?
2、List的实现类的底层原理?
迭代器(Iterator)
增强for循环(foreach)
Lambda表达式
for循环(因为List集合存在索引)
package com.app.d5_collection_list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
目标:总结List系列集合的遍历方式
*/
public class ListDemo2 {
public static void main(String[] args) {
// 多态写法
List<String> list = new ArrayList<>();
list.add("JavaSE01");
list.add("JavaSE02");
list.add("JavaSE03");
// 1、for循环遍历(List系列集合独有的遍历方式)
System.out.println("1、for循环遍历(List系列集合独有的遍历方式):");
for (int i = 0; i < list.size(); i++) {
String ele = list.get(i);
System.out.println(ele);
}
System.out.println("---------------------------");
// 2、迭代器(Iterator)
System.out.println("2、迭代器(Iterator):");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String ele = it.next();
System.out.println(ele);
}
System.out.println("---------------------------");
// 3、增强for循环(foreach)
System.out.println("3、增强for循环(foreach):");
for (String ele : list) {
System.out.println(ele);
}
System.out.println("---------------------------");
// 4、JDK 1.8之后的Lambda表达式
System.out.println("4、Lambda表达式:");
list.forEach(
ele -> System.out.println(ele)
);
}
}
1、for循环遍历(List系列集合独有的遍历方式):
JavaSE01
JavaSE02
JavaSE03
---------------------------
2、迭代器(Iterator):
JavaSE01
JavaSE02
JavaSE03
---------------------------
3、增强for循环(foreach):
JavaSE01
JavaSE02
JavaSE03
---------------------------
4、Lambda表达式:
JavaSE01
JavaSE02
JavaSE03
Process finished with exit code 0
ArrayList底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。
第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。
方法 | 说明 |
---|---|
public void addFirst(E e) | 在此列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
Public E removeLast() | 从此列表中删除并返回最后一个元素 |
package com.app.d5_collection_list;
import java.util.LinkedList;
import java.util.List;
/**
目标:掌握List系列集合的 LinkedList集合的特有方法(API)
*/
public class ListDemo3 {
public static void main(String[] args) {
// 1、创建一个LinkedList集合
// 它可以完成队列、栈结构(双链表)
// 栈:后进先出,先进后出
// 因为需要用它自己独有的方法,因此不适合多态写法
// List list = new LinkedList<>();
LinkedList<String> stack = new LinkedList<>();
// a、上弹(压栈,入栈)
// 压栈,入栈API:public void push(E e):方法内部包装了一个 addFirst()方法,效果一样
stack.push("第1颗子弹");
stack.push("第2颗子弹"); // 但是入栈用push,显得专业、B格高
stack.push("第3颗子弹");
stack.addFirst("第4颗子弹");
System.out.println(stack);
// b、打出子弹(弹栈,出栈)
// 弹栈,出栈API:public E pop():方法内部包装了一个 removeFirst()方法,效果一样
System.out.println(stack.pop() + "已打出~~"); // 但是出栈用pop,显得专业、B格高
System.out.println(stack.pop() + "已打出~~");
System.out.println(stack.removeFirst() + "已打出~~");
// c、弹夹中剩余子弹
System.out.println(stack);
System.out.println("--------------------------------");
// 队列:后进后出,先进先出
LinkedList<String> queue = new LinkedList<>();
// a、入队
queue.addLast("第1个人");
queue.addLast("第2个人");
queue.addLast("第3个人");
queue.addLast("第4个人");
System.out.println(queue);
// b、出队
System.out.println(queue.removeFirst() + "已出队~~");
System.out.println(queue.removeFirst() + "已出队~~");
System.out.println(queue.removeFirst() + "已出队~~");
// c、队列中剩余人数
System.out.println(queue);
}
}
[第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]
第4颗子弹已打出~~
第3颗子弹已打出~~
第2颗子弹已打出~~
[第1颗子弹]
--------------------------------
[第1个人, 第2个人, 第3个人, 第4个人]
第1个人已出队~~
第2个人已出队~~
第3个人已出队~~
[第4个人]
Process finished with exit code 0
从集合中的一批元素中找出某些数据并删除,如何操作?是否存在问题?
迭代器、增强for循环遍历集合,并且直接用集合删除元素的时候可能出现。
package com.app.d6_collection_update_delete;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
目标:学会解决集合的并发修改异常
*/
public class Test {
public static void main(String[] args) {
// 1、创建一个ArrayList集合
// 多态写法
List<String> list = new ArrayList<>();
list.add("biubiu~~");
list.add("biubiu~~");
list.add("甄子丹");
list.add("甄子丹");
list.add("JavaSE");
System.out.println(list); // [biubiu~~, biubiu~~, 甄子丹, 甄子丹, JavaSE]
// 2、需求:删除全部 ”甄子丹”
// a、迭代器
// 获取迭代器
/*Iterator it = list.iterator();
// 问一下有没有数据?
while (it.hasNext()) {
// 有数据,存一下
String ele = it.next();
if ("甄子丹".equals(ele)) { // 问一下这个数据 是否与 “甄子丹” 相等??
// 相同,删除掉
// bug: 迭代器直接使用集合的方法删除,会出现并发修改异常错误,但是可以解决
// list.remove("甄子丹");
// 解决方案:直接使用迭代器的方法删除,因为它的方法在底层做了处理
it.remove();
}
}
System.out.println(list); // [biubiu~~, biubiu~~, JavaSE]*/
// b、增强for循环(foreach)
/*for (String ele : list) {
if ("甄子丹".equals(ele)) {
// bug: foreach直接使用集合的方法删除,会出现并发修改异常错误,无法解决
// 因为foreach的底层也是for循环,并且没有做过处理,因此无法解决
list.remove(ele);
}
}*/
// c、Lambda表达式(forEach)
/*list.forEach(ele -> {
if ("甄子丹".equals(ele)) {
// bug: forEach直接使用集合的方法删除,会出现并发修改异常错误,无法解决
// 因为forEach的底层也是for循环,并且没有做过处理,因此无法解决
list.remove(ele);
}
});*/
// d、for循环(for循环直接使用集合的方法删除,不会出现并发修改异常错误,但是也存在bug(会漏掉数据),不过有解决方案)
/*for (int i = 0; i < list.size(); i++) {
String ele = list.get(i);
if ("甄子丹".equals(ele)) {
// bug: for循环直接使用集合的方法删除,不会出现并发修改异常错误
// 但是也存在bug(会漏掉数据),不过有解决方案
// 因为如果集合中有许多个 “甄子丹”,删除一个,下一个就会上来,但是i已经往前++了,因此会漏掉数据
list.remove(ele);
}
}
System.out.println(list);*/
// 解决方案1:倒着删除
/*
list.size-1 : 集合个数-1(最后一个位置)
i >= 0 : 判断条件(必须大于等于0)
i-- : 倒着走
*/
/*for (int i = list.size()-1; i >= 0; i--) {
String ele = list.get(i);
if ("甄子丹".equals(ele)) {
list.remove(ele);
}
}
System.out.println(list);*/
// 解决方案2:每删除掉一个甄子丹,就往后移一个位置
for (int i = 0; i < list.size(); i++) {
String ele = list.get(i);
if ("甄子丹".equals(ele)) {
list.remove(ele);
i--; // 每删除掉一个甄子丹,往后移一个位置
}
}
System.out.println(list);
}
}
[biubiu~~, biubiu~~, 甄子丹, 甄子丹, JavaSE]
[biubiu~~, biubiu~~, JavaSE]
Process finished with exit code 0
哪种遍历删除元素不会出现bug?