学习笔记使用
ArrayList特点:动态数组结构,元素有序,可重复的一个集合
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestForeach {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("a");
words.add("b");
words.add("c");
words.add("c");
words.add("d");
words.add("e");
// 方案一:通过for循环
for (int i = 0;i<words.size();i++){
if ("a".equals(words.get(i))){
words.remove(i);
}
}
// 方案二:通过一个迭代器
Iterator<String> iterator = words.iterator();
while (iterator.hasNext()){
String word = iterator.next();
if ("e".equals(word)){
iterator.remove();
}
}
// 通过流的方式打印输出
words.stream().forEach(System.out::println);
}
}
运行结果:
b
c
c
d
上图代码,是for循环和迭代器删除不重复的元素,安全删除元素。
import java.util.ArrayList;
import java.util.List;
public class TestForeach {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("a");
words.add("b");
words.add("c");
words.add("c");
words.add("d");
words.add("e");
// 方案一:通过for循环
for (int i = 0;i<words.size();i++){
if ("c".equals(words.get(i))){
words.remove(i);
}
}
// 通过流的方式打印输出
words.stream().forEach(System.out::println);
}
}
运行结果:
a
b
c
d
e
上图代码,是for循环删除指定的重复元素, 但是删除不安全,运行结果还有一个C 原因是动态数组结构
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestForeach {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("a");
words.add("b");
words.add("c");
words.add("c");
words.add("d");
words.add("e");
// 方案二:通过一个迭代器
Iterator<String> iterator = words.iterator();
while (iterator.hasNext()){
String word = iterator.next();
if ("c".equals(word)){
iterator.remove();
}
}
// 通过流的方式打印输出
words.stream().forEach(System.out::println);
}
}
运行结果:
a
b
d
e
上图代码:迭代器删除指定重复元素,安全删除
对比发现,如果使用for循环,在list集合中删除相同的元素会发现删除不干净,而对比使用迭代器可以删除相同的元素。
import java.util.ArrayList;
import java.util.List;
public class TestForeach {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("a");
words.add("b");
words.add("c");
words.add("c");
words.add("d");
words.add("e");
// 方案三:使用增强for循环
for (String word : words){
if ("c".equals(word)){
words.remove(word);
}
}
// 通过流的方式打印输出
words.stream().forEach(System.out::println);
}
}
运行结果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at 经典面试题.TestForeach.main(TestForeach.java:40)
上图代码是增强for循环,删除指定的重复元素,但是抛出异常报错,
由图可知:只要modCount != expectedModCount就会抛出异常,那我们只要关心一下两个值为什么不相等,在集合对其进行添加和修改时都会修改modCount值,在遍历之前modCount值是6,一开始modCount 与expectedModCount是相等的,在循环的过程中会删除一个元素,这时modCount与expectedModCount就不相等,因此会抛出异常。
二:下面为 安全删除指定重复元素
import java.util.ArrayList;
import java.util.List;
public class TestForeach {
public static void main(String[] args) {
List<String> words = new ArrayList<>();
words.add("a");
words.add("b");
words.add("c");
words.add("c");
words.add("d");
words.add("e");
// 方案四:采用removeIf接口,里面传上一个lambda表达式
words.removeIf(word ->word.equals("c"));
// 通过流的方式打印输出
words.stream().forEach(System.out::println);
}
}
运行结果:
a
b
d
e
上图为jdk8的优化:
Java安全删除集合元素jdk8的终极解决方案:采用removeIf接口
//倒序删除,以防因为删除中间项导致数据下标变更,使得数据出错
public static void remove2(List<String> list) {
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i).contains("3")) {
list.remove(i);
}
}
}
顺序list集合删除
// 顺序删除,但是对下标和索引进行了处理
public static void remove3(List<String> list) {
for (int i = 0, len = list.size(); i < len; i++) {
if (list.get(i).contains("3")) {
list.remove(i);
len--;
i--;
}
}
}
总结:
安全删除元素:
顺序,倒序都能删除指定的重复元素,案例在下面的源码里(remove2,remove3方法)
使用普通for循环可以删除不相同元素
可以使用迭代器删除元素
使用jdk8推出的新接口removeIf接口
不安全删除元素:
使用普通for循环删除相同元素会删除不干净
使用增强for循环删除元素会抛出并发修改异常
注意:不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。
package com.numberone.web;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> strs = new ArrayList<>();
strs.add("1");
strs.add("32");
strs.add("3");
strs.add("4");
strs.add("5");
strs.add("36");
strs.add("3");
strs.add("3");
System.out.println("删除元素前"+strs.size());
System.out.println("删除元素前"+strs);
// remove1(strs);
// remove9(strs);
// remove2(strs);
remove3(strs);
// remove4(strs);
System.out.println("删除元素后"+strs);
System.out.println("删除元素后"+strs.size());
// printList(strs);
//
}
//使用iterator,这个是java和Android源码中经常使用到的一种方法,所以最为推荐
public static void remove1(List<String> list) {
Iterator<String> sListIterator = list.iterator();
while (sListIterator.hasNext()) {
String str = sListIterator.next();
if (str.contains("3")) {
sListIterator.remove();
}
}
}
//不安全
public static void remove9(List<String> list){
for (int i=0;i<list.size();i++){
if (list.get(i).contains("3")) {
list.remove(i);
}
}
}
//倒序删除,以防因为删除中间项导致数据下标变更,使得数据出错
public static void remove2(List<String> list) {
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i).contains("3")) {
list.remove(i);
}
}
}
// 顺序删除,但是对下标和索引进行了处理
public static void remove3(List<String> list) {
for (int i = 0, len = list.size(); i < len; i++) {
if (list.get(i).contains("3")) {
list.remove(i);
len--;
i--;
}
}
}
// 在遍历过程中不直接操作原list
public static void remove4(List<String> list) {
List<String> temp = new ArrayList<>();
for (String str : list) {
if (str.contains("3")) {
temp.add(str);
}
}
list.removeAll(temp);
}
public static void printList(List<String> list) {
for (String str : list) {
System.out.println(str);
}
}
}