List系列集合的特点:
- ArrayList、LinekdList:有序,可重复,有索引。
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
List集合特有方法:List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。
方法名称 | 说明 |
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
import java.util.ArrayList;
import java.util.List;
public class ListDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("java");
list.add("MySQL");
list.add("MySql");
//2、在某个索引位置插入元素
list.add(2,"HTML");
System.out.println(list);//[Java, java, HTML, MySQL, MySql]
//3、根据索引删除元素,返回被删除元素
System.out.println(list.remove(2));//HTML
System.out.println(list);//[Java, java, MySQL, MySql]
//4、根据索引获取元素:public E get(int index):返回集合中指定位置的元素
System.out.println(list.get(2));//MySQL
//5、修改索引位置处的元素:public E set(int index, E element)
//返回修改前的数据
System.out.println(list.set(1,"老番茄"));//java
System.out.println(list);//[Java, 老番茄, MySQL, MySql]
}
}
List的实现类的底层原理:
- ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢(相对,实际还行其实)。
- LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的。
List集合的遍历方式:
- 迭代器
- 增强for循环
- Lambda表达式
- for循环(因为List集合存在索引)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("java");
list.add("MySQL");
list.add("MySql");
//1、for循环
System.out.println("-----------------");
for (int i = 0; i < list.size(); i++) {
String ele = list.get(i);
System.out.println(ele);
}
//2、迭代器
System.out.println("------------------");
Iterator<String> it = list.iterator();
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
//3、foreach
System.out.println("------------------");
for (String s : list) {
System.out.println(s);
}
//4、Lambda表达式
System.out.println("--------------------");
list.forEach(s -> {
System.out.println(s);
});
}
}
ArrayList集合底层原理:
- ArrayList底层是基于数组实现的:根据索引定位元素块,增删需要做元素的移位操作。
- 第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。使用size记录当前元素的个数,也是下一个元素插入的位置。如果超过容量,会按照当前容量的1.5倍扩容。
LinkedList的特点:
- 底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkedList集合的特有功能:
方法名称 | 说明 |
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
import java.util.LinkedList;
public class ListDemo3 {
public static void main(String[] args) {
//栈
LinkedList<String> stack = new LinkedList<>();
//压栈、入栈stack.push() 里面写的就是 stack.addFirst()
stack.addFirst("第一颗子弹");//stack.push("第一颗子弹");
stack.addFirst("第二颗子弹");//stack.push("第二颗子弹");
stack.addFirst("第三颗子弹");//stack.push("第三颗子弹");
stack.addFirst("第四颗子弹");//stack.push("第四颗子弹");
System.out.println(stack); //[第四颗子弹, 第三颗子弹, 第二颗子弹, 第一颗子弹]
//出栈,弹栈stack.pop() 里面写的就是stack.removeFirst()
System.out.println(stack.removeFirst());//第四颗子弹
System.out.println(stack.pop());//第三颗子弹
System.out.println(stack.pop());//第二颗子弹
System.out.println(stack);//[第一颗子弹]
//队列
LinkedList<String> queue = new LinkedList<>();
queue.addLast("1号");
queue.addLast("2号");
queue.addLast("3号");
queue.addLast("4号");
System.out.println(queue);//[1号, 2号, 3号, 4号]
//出队
System.out.println(queue.removeFirst());//1号
System.out.println(queue.removeFirst());//2号
System.out.println(queue.removeFirst());//3号
System.out.println(queue);//[4号]
}
}
集合的并发修改异常问题:当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题。
存在问题的遍历:
- 迭代器遍历集合且直接用集合删除元素的时候可能出现。
- 增强for循环遍历集合且直接用集合删除元素的时候可能出现。
删除元素不出问题的遍历:
- 迭代器遍历集合但是用迭代器自己的删除方法操作可以解决。
- 使用for循环遍历并删除元素不会存在这个问题。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo4 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("java");
list.add("java");
list.add("MySQL");
list.add("MySql");
System.out.println(list);//[Java, java, MySQL, MySql]
//需求:删除全部的Java信息
//1、迭代器遍历删除
// Iterator<String> it = list.iterator();
// while(it.hasNext()){
// String ele = it.next();
// if("java".equals(ele)){
// list.remove("java");//(会出现bug)报错ConcurrentModificationException
it.remove();//使用迭代器删除当前位置的元素,保证索引不后移,能够成功删除所有的java,遍历到全部元素
// }
// }
//2、foreach遍历删除(会出现bug)
// for (String s : list) {
// if("java".equals(s)){
// list.remove("java");//报错ConcurrentModificationException
// }
// }
//3、lambda遍历删除(会出现bug)
// list.forEach(s -> {
// if("java".equals(s)){
// list.remove("java");//报错ConcurrentModificationException
// }
// });
//4、for循环删除不报错,但从前往后删会漏删元素
// for (int i = 0; i < list.size(); i++) {
// String ele = list.get(i);
// if("java".equals(ele)){
// list.remove("java");
// }
// }
// System.out.println(list);//[Java, java, MySQL, MySql]
//解决方案:从后往前删
// for (int i = list.size()-1; i >=0; i--) {
// String ele = list.get(i);
// if("java".equals(ele)){
// list.remove("java");
// }
// }
// System.out.println(list);//[Java, MySQL, MySql]
//解决方案2
for (int i = 0; i < list.size(); i++) {
String ele = list.get(i);
if("java".equals(ele)){
list.remove("java");
i--;
}
}
System.out.println(list);//[Java, MySQL, MySql]
}
}