Java根据条件删除Map中元素

本文讨论了Java中Map数据结构在多线程环境下删除元素时出现的并发修改异常,解释了原因并提供了避免该问题的方法。

今天在写程序过程中,需要根据判断条件删除一个Map中的相应数据,我自然而然想到可以通过调用Map中的remove(Object key)函数进行删除:代码如下:

public Map<Double, Double> processMap(Map<Double, Double> list) {

Map<Double, Double> map = list;

Iterator<Double> iter = map.keyset().iterator;

while(iter.hasNext()) {

double key = iter.next();

if (key > 5)

map.remove(key);

}

return map;

}

但是运行程序的时候却没有正常删除元素,而是提示“java.util.ConcurrentModificationException”错误,很是疑惑,于

是找了一些关于Map的资料发现:Map的实现不是同步的如果程序中出现多个线程同时访问一个Map,而其中至少一个线程修改Map

时,它必须保持外部同步。而通过查看Iterator原理发现,Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说

Iterator在工作的时候,是不允许被迭代的对象被改变的,所以调用Iterator操作获得的对象在多线程修改Map的时候会自动失效。

Iterator被创建的时候,建立了一个内存索引表(单链表),这 个索引表指向原来的对象,当原来的对象数量改变的时候,这个索

引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错 误。Map、List、Set等是动态

的,可变对象数量的数据结构,但是Iterator则是单向不可变,只能顺序读取,不能逆序操作的数据结构,当 Iterator指向的原始

数据发生变化时,Iterator自己就迷失了方向。

既然找到了问题的原因,那么如何解决呢?可以通过调用Iterator的remove(Object o)函数来移除元素。

测试代码如下:

public Map<Double, Double> processMap(Map<Double, Double> list) {

Map<Double, Double> map = list;

Iterator<Double> iter = map.keyset().iterator;

while(iter.hasNext()) {

double key = iter.next();

if (key > 5) {

//   map.remove(key);  // java.util.ConcurrentModificationException

iter.remove(key);  // OK

}

}

return map;

}


同时,在遍历Map过程中,调用put(key, value)函数来添加元素,也会出现同样的问题,所以同样需要使用迭代器的相应函数来添加。


Java 流中不能直接删除 Map 中的元素,因为流本身是对数据源的抽象,不改变数据源。不过可以通过流筛选出需要保留的元素,然后创建一个新的 Map 来间接实现删除操作。以下为几种常见的实现方式: ### 使用 Stream 和 Collectors.toMap ```java import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "value1"); map.put(2, "value2"); map.put(3, "value3"); // 筛选出键不等于 2 的元素,创建新的 Map Map<Integer, String> newMap = map.entrySet().stream() .filter(entry -> entry.getKey() != 2) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); System.out.println(newMap); } } ``` 上述代码中,使用 `stream()` 方法将 `entrySet()` 转换为流,接着用 `filter` 方法筛选出键不等于 2 的元素,最后用 `Collectors.toMap` 方法将筛选后的元素收集到新的 `Map` 中。 ### 结合 removeIf 和流操作 ```java import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "value1"); map.put(2, "value2"); map.put(3, "value3"); // 筛选出需要删除元素的键 map.keySet().removeIf(key -> key == 2); System.out.println(map); } } ``` 这里通过 `removeIf` 方法直接从 `keySet` 中删除符合条件的键,从而间接删除了 `Map` 中对应的元素。 ### 使用 Stream 和 Collectors.groupingBy ```java import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { Map<Integer, String> map = new HashMap<>(); map.put(1, "value1"); map.put(2, "value2"); map.put(3, "value3"); // 分组操作,将符合条件和不符合条件元素分开 Map<Boolean, Map<Integer, String>> partitionedMap = map.entrySet().stream() .collect(Collectors.groupingBy( entry -> entry.getKey() != 2, Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue) )); // 获取保留的元素 Map<Integer, String> newMap = partitionedMap.get(true); System.out.println(newMap); } } ``` 该代码使用 `Collectors.groupingBy` 方法将元素分为符合条件和不符合条件的两组,然后获取保留的元素组成新的 `Map`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值