看到这么标题可能觉得这个真是太easy了,不就remove吗,分分钟搞定。
但结果却出乎意料,下面我们来j简单说说list删除数据可能遇到的坑:
先说明我们可能会遇到的两个问题:
1.java.lang.IndexOutOfBoundsException(索引越界)
2.java.util.ConcurrentModificationException(并发修改异常)
开始测试:
首先初始化一个List<Map<String,String>>
package test02;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/*
* List<Map<String,String>> 删除元素常见的误区
*
*/
public class Test09 {
public static void main(String[] args) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Map<String, String> map1=new HashMap<>();
Map<String, String> map2=new HashMap<>();
Map<String, String> map3=new HashMap<>();
Map<String, String> map4=new HashMap<>();
map1.put("key","张三");
map1.put("value","20");
map2.put("key","李四");
map2.put("value","25");
map3.put("key","王五");
map3.put("value","30");
map4.put("key","张三");
map4.put("value","35");
list.add(map1);
list.add(map2);
list.add(map3);
list.add(map4);
for (int i = 0; i < list.size(); i++) {
System.out.println("初始化遍历:"+list.get(i));
}
}
}
需求:删除这个list里面,key为张三的数据;
方式一:for i 循环 通过索引使用:list.remove(i)删除;
for (int i = 0; i < list.size(); i++) {
System.out.println("i:"+i);
System.out.println("len:"+list.size());
String a = String.valueOf(list.get(i).get("key"));
if(a.equals("张三")) {
list.remove(i);
System.out.println("第"+i+"次循环删除成功");
System.out.println("删除后长度:"+list.size());
}
System.out.println("方式一遍历:"+list.get(i));
}
出现异常报错:java.lang.IndexOutOfBoundsException(索引越界)
原因:每次循环删除元素之后,初始长度已发生变化,在最后一次循环出现越界
打印输出分析:
i:0
len:4
第0次循环删除成功
删除后长度:3
方式一遍历:{value=25, key=李四}
i:1
len:3
方式一遍历:{value=30, key=王五}
i:2
len:3
第2次循环删除成功
删除后长度:2
Exception in thread “main” java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 2
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
at java.base/java.util.Objects.checkIndex(Objects.java:359)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at test01/test02.Test09.main(Test09.java:62)
方式二:foreach循环:list.remove(map)删除
for(Map<String, String> map :list) {
String a = String.valueOf(map.get("key"));
if(a.equals("张三")) {
list.remove(map);
}
System.out.println("方式二遍历:"+map);
}
出现异常报错:java.util.ConcurrentModificationException(并发修改异常)
通过源码分析:发现在 next、remove方法中都会调用checkForComodification 方法,
该方法的 作用是判断 modCount != expectedModCount是否相等,
如果不相等则抛出ConcurrentModificationException异常;
当我们调用 list.remove(item)时,对 list 对象的 modCount 值进行了修改;
而 list 对象的迭代器的 expectedModCount 值未进行修改;
所以就抛出ConcurrentModificationException异常!
private class Itr implements Iterator {
int cursor; // 要返回的下一个元素的索引
int lastRet = -1; // 返回的最后一个元素的索引;如果没有就返回-1
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
方式三:Stream流:filter(推荐)
list = list.stream().filter(e -> (!e.get("key").equals("张三"))).collect(Collectors.toList());
for (int i = 0; i < list.size(); i++) {
System.out.println("方式三遍历:"+list.get(i));
}
输出:
方式三遍历:{value=25, key=李四}
方式三遍历:{value=30, key=王五}
方式四:迭代器iterator的remove方法(使用更加灵活)
Iterator<Map<String, String>> iterator = list.iterator();
while (iterator.hasNext()){
Map<String, String> next = iterator.next();
String key = String.valueOf(next.get(("key")));
if(key.equals("张三")){
iterator.remove();
}
}
for (Map<String, String> map : list) {
System.out.println("方式四遍历:"+map);
}
输出:
方式四遍历:{value=25, key=李四}
方式四遍历:{value=30, key=王五}
简单总结:文章来源:https://www.toymoban.com/news/detail-522050.html
1、用for循环遍历List删除元素时,需要注意索引变化(左移或右移)的问题(不推荐)。
2、List删除元素时,默认按索引删除,而不是对象删除(不推荐)。
3、List删除元素时,为避免陷阱,建议使用Stream流的filter方式(推荐)。
3、List删除元素时,为避免陷阱,建议使用迭代器iterator的remove方式(推荐)。文章来源地址https://www.toymoban.com/news/detail-522050.html
到了这里,关于<List<Map<String,String>>> 删除元素常见的误区的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!