[英]Iterator.remove() not removing
我在使用没有抛出异常的迭代器的remove()
方法时遇到了一个问题,但该方法根本无法按预期工作。
有一个Map<List<Integer>, Integer>
包含:
{[1, 2]=3, [2, -1]=1, [-4]=-4, [-1, 0, 1]=0, [-1, -4]=-5, [0, 1, -1]=0}
容易出问题的线路是:
map.entrySet().removeIf(e -> e.getKey().size() < 3 || e.getValue() != 0);
我用谷歌搜索了很多,但仍然无法弄清楚。
完整代码如下:
public class Main {
public static void main(String[] args){
int[] nums = {-1, 0, 1, 2, -1, -4};
Solution sol = new Solution();
Map<List<Integer>, Integer> map = sol.threeSum(nums);
Iterator<Map.Entry<List<Integer>, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<List<Integer>, Integer> m = it.next();
System.out.println(m.getKey().size());
}
map.entrySet().removeIf(e -> e.getKey().size() < 3 || e.getValue() != 0);
System.out.println(map);
}
}
class Solution {
public Map<List<Integer>, Integer> threeSum(int[] nums) {
HashMap<List<Integer>, Integer> map = new HashMap<List<Integer>, Integer>();
for (int num : nums) {
Iterator<Map.Entry<List<Integer>, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<List<Integer>, Integer> e = it.next();
if (e.getKey().size() == 2) {
if (e.getKey().get(0) + e.getKey().get(1) + num != 0) {
it.remove();
} else {
e.getKey().add(num);
e.setValue(0);
}
} else if (e.getKey().size() == 1) {
e.getKey().add(num);
e.setValue(e.getKey().get(0) + num);
}
}
List<Integer> li = new ArrayList<Integer>();
li.add(num);
map.put(li, num);
}
System.out.println(map);
return map;
}
}
Thanks to @PrasadU I compared the remove
method of HashMap, and I find out the problem is caused by the recalculation of hash value in java8 (When I add new element in the list, the hash value of that node changes but the position remains the同样,因此通过重新计算 hash 我们找不到节点),而在 java 11 中它不会重新计算。
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
removeNode(p.hash, p.key, null, false, false);
expectedModCount = modCount;
}
很高兴得到纠正-
JDK 8 存在一些问题和行为差异。如果集合的大小在 JDK 8 中大于 1,则删除 function 似乎无法按预期工作。
JDK 11 相同的代码按预期工作。
我将代码缩减为更小的 function。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MapRemove2 {
public static void main(String[] args) {
testRemove(1);
testRemove(2);
}
private static void testRemove(int limit) {
System.out.println("LIMIT = " + limit + "\n---------");
Map<List<Integer>, Integer> map = new HashMap<List<Integer>, Integer>();
for (int i = 0; i < 5; i++) {
map.entrySet().removeIf(e -> e.getKey().size() == limit);
System.out.println(String.format("LOOP %2d - map after remove = %s", i, map));
int finalI = i;
map.entrySet().forEach(e -> {
e.getKey().add(finalI);
e.setValue(e.getValue() + finalI);
});
List<Integer> li = new ArrayList<Integer>();
li.add(i);
map.put(li, i);
System.out.println(String.format("LOOP %2d - map after add = %s", i, map));
}
System.out.println("Final MAP " + map + "\n----------\n\n");
}
}
在 JDK 8 1.8.0_212(编译+运行)结果是
> Task :MapRemove2.main()
LIMIT = 1
---------
LOOP 0 - map after remove = {}
LOOP 0 - map after add = {[0]=0}
LOOP 1 - map after remove = {}
LOOP 1 - map after add = {[1]=1}
LOOP 2 - map after remove = {}
LOOP 2 - map after add = {[2]=2}
LOOP 3 - map after remove = {}
LOOP 3 - map after add = {[3]=3}
LOOP 4 - map after remove = {}
LOOP 4 - map after add = {[4]=4}
Final MAP {[4]=4}
----------
LIMIT = 2
---------
LOOP 0 - map after remove = {}
LOOP 0 - map after add = {[0]=0}
LOOP 1 - map after remove = {[0]=0}
LOOP 1 - map after add = {[1]=1, [0, 1]=1}
LOOP 2 - map after remove = {[1]=1, [0, 1]=1}
LOOP 2 - map after add = {[1, 2]=3, [2]=2, [0, 1, 2]=3}
LOOP 3 - map after remove = {[1, 2]=3, [2]=2, [0, 1, 2]=3}
LOOP 3 - map after add = {[1, 2, 3]=6, [2, 3]=5, [3]=3, [0, 1, 2, 3]=6}
LOOP 4 - map after remove = {[1, 2, 3]=6, [2, 3]=5, [3]=3, [0, 1, 2, 3]=6}
LOOP 4 - map after add = {[1, 2, 3, 4]=10, [2, 3, 4]=9, [3, 4]=7, [4]=4, [0, 1, 2, 3, 4]=10}
Final MAP {[1, 2, 3, 4]=10, [2, 3, 4]=9, [3, 4]=7, [4]=4, [0, 1, 2, 3, 4]=10}
----------
在 JDK 11 中(编译并运行)
任务:MapRemove2.main()
LIMIT = 1
---------
LOOP 0 - map after remove = {}
LOOP 0 - map after add = {[0]=0}
LOOP 1 - map after remove = {}
LOOP 1 - map after add = {[1]=1}
LOOP 2 - map after remove = {}
LOOP 2 - map after add = {[2]=2}
LOOP 3 - map after remove = {}
LOOP 3 - map after add = {[3]=3}
LOOP 4 - map after remove = {}
LOOP 4 - map after add = {[4]=4}
Final MAP {[4]=4}
----------
LIMIT = 2
---------
LOOP 0 - map after remove = {}
LOOP 0 - map after add = {[0]=0}
LOOP 1 - map after remove = {[0]=0}
LOOP 1 - map after add = {[1]=1, [0, 1]=1}
LOOP 2 - map after remove = {[1]=1}
LOOP 2 - map after add = {[1, 2]=3, [2]=2}
LOOP 3 - map after remove = {[2]=2}
LOOP 3 - map after add = {[2, 3]=5, [3]=3}
LOOP 4 - map after remove = {[3]=3}
LOOP 4 - map after add = {[3, 4]=7, [4]=4}
Final MAP {[3, 4]=7, [4]=4}
----------
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.