我的位置:首頁 >   > 

    [Java]在Java中限制Map數量,若超過移除舊資料

    發表時間:
    一般來說使用MAP時就算限定了數量

    new HashMap<Integer,Integer>(10)

    但是在使用put的時候會連帶使用到addEntry

    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

    然而在addEntry當中會判斷如果MAP中的數量大於限定數量時

    void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }

    會去使用resize進行擴充,而擴充的數量是限定的兩倍

    void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }

    也就是說就算一開始設定了數量為10,當裡面的元素超過10之後會自動變成20

    要解決這個問題最直覺的作法就是去覆寫put

    不過看到put原本的內容.....

    我沒有把握弄改好..還是不要亂來吧

    後來發現HashMap下面還有一個子類別叫做LinkedHashMap

    它跟HashMap不同的地方是LinkedHashMap會去紀錄新增的順序,但HashMap不會

    LinkedHashMap中有一個函式叫做removeEldestEntry

    從字面上來翻譯,就是移除最舊項目

    官方API文件也給了一個覆寫範例

    private static final int MAX_ENTRIES = 100;

    protected boolean removeEldestEntry(Map.Entry eldest) {

        return size() > MAX_ENTRIES;

    }

    如果數量超過一百就移除最先put進來的元素

    這不就是我們需要的東西嗎!!!

    馬上來測試看看

    Map<Integer,Integer> h = new LinkedHashMap<Integer,Integer>(){
        private static final int MAX_ENTRIES = 10;
        
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > MAX_ENTRIES;
        }
    };

    for(int i = 1; i < 21; i++){
        h.put(new Integer(i), new Integer(i));
    }

    System.out.println(h.size());

    最後輸出的結果是10

    但如果把LinkedHashMap改成HashMap會輸出20