簡體   English   中英

Iterator.remove() 不刪除

[英]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 中它不會重新計算。

  • java8
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;
        }
  • java11
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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM