java 如何通过在达到限制时删除最旧的条目来限制地图的最大大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11469045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:14:07  来源:igfitidea点击:

How to limit the maximum size of a Map by removing oldest entries when limit reached

javacachingcollectionsmap

提问by matt burns

I want an implementation of Map that has a maximum size. I want to use this as a cache and so oldest entries are removed once limit has been reached.

我想要一个具有最大尺寸的 Map 实现。我想将其用作缓存,因此一旦达到限制,将删除最旧的条目。

I also don't want to introduce a dependency on any 3rd party libraries.

我也不想引入对任何 3rd 方库的依赖。

回答by Peter Lawrey

You can use LinkedHashMaplike this

您可以像这样使用LinkedHashMap

You can remove by LRU or FIFO.

您可以通过 LRU 或 FIFO 删除。

public static <K, V> Map<K, V> createLRUMap(final int maxEntries) {
    return new LinkedHashMap<K, V>(maxEntries*10/7, 0.7f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
            return size() > maxEntries;
        }
    };
}

回答by matt burns

Here is an implementation that just wraps a normal HashMap and delegates the method calls to it. The only difference is that the Map cannot grow beyond the maximum capacity.

这是一个仅包装普通 HashMap 并将方法调用委托给它的实现。唯一的区别是 Map 不能增长超过最大容量。

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

public class CacheMap<K, V> implements Map<K, V> {

    private final Map<K, V> delegate = new HashMap<K, V>();
    private Queue<K> keyInsertionOrder = new LinkedList<K>();
    private final int maxCapacity;

    public CacheMap(int maxCapacity) {
        if (maxCapacity < 1) {
            throw new IllegalArgumentException(
                    "Capacity must be greater than 0");
        }
        this.maxCapacity = maxCapacity;
    }

    @Override
    public void clear() {
        delegate.clear();
    }

    @Override
    public boolean containsKey(Object key) {
        return delegate.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return delegate.containsValue(value);
    }

    @Override
    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return delegate.entrySet();
    }

    @Override
    public boolean equals(Object o) {
        return delegate.equals(o);
    }

    @Override
    public V get(Object key) {
        return delegate.get(key);
    }

    @Override
    public int hashCode() {
        return delegate.hashCode();
    }

    @Override
    public boolean isEmpty() {
        return delegate.isEmpty();
    }

    @Override
    public Set<K> keySet() {
        return delegate.keySet();
    }

    @Override
    public V put(K key, V value) {
        V previous = delegate.put(key, value);
        keyInsertionOrder.remove(key);
        keyInsertionOrder.add(key);

        if (delegate.size() > maxCapacity) {
            K oldest = keyInsertionOrder.poll();
            delegate.remove(oldest);
        }
        return previous;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        for (K key : m.keySet()) {
            put(key, m.get(key));
        }
    }

    @Override
    public V remove(Object key) {
        keyInsertionOrder.remove(key);
        return delegate.remove(key);
    }

    @Override
    public int size() {
        return delegate.size();
    }

    @Override
    public Collection<V> values() {
        return delegate.values();
    }
}

回答by Denys Séguret

I use a personal class which does what you need. Once the map is full, oldest accessed objects are removed when inserting. It uses a hashmap and a linked list.

我使用个人课程来满足您的需求。一旦映射已满,插入时将删除最早访问的对象。它使用哈希图和链表。

You have two methods to read :

您有两种阅读方法:

  • peek (which doesn't mark the object as recently accessed)
  • get (which mark the object as recently accessed and thus prevents its removal for a time)
  • peek(不会将对象标记为最近访问过)
  • get(将对象标记为最近访问过,从而在一段时间内阻止其删除)

Here's the class (comments removed because they were in French) :

这是课程(评论被删除,因为它们是法语):

import java.util.HashMap;
import java.util.Map;

public final class HashCache<K, T> {

    public interface Disposer<T> {
        void dispose(T t);
    }

    class Maillon {
        public K cle;

        public Maillon precedent;
        public Maillon suivant;
        public T contenu;
    }

    private Map<K, Maillon> barrette = new HashMap<K, Maillon>();

    private Maillon sommet;
    private Maillon fond;
    private int tailleCache = 100;

    private Disposer<T> disposer;

    @SuppressWarnings("unchecked")
    public HashCache(int tailleCache) {
        if (tailleCache>2) this.tailleCache = tailleCache;
        Maillon[] maillons = new HashCache.Maillon[tailleCache];
        sommet = maillons[0] = new Maillon();
        for (int i=1; i<tailleCache; i++) (maillons[i-1].suivant = maillons[i] = new Maillon()).precedent = maillons[i-1];
        fond = maillons[tailleCache-1];
        //check();
    }

    public Object getLastRead() {
        return sommet.contenu;
    }

    public Object peek(K cle) {
        Object m = barrette.get(cle);
        if (m==null) return null;
        return ((Maillon) m).contenu;
    }

    public synchronized void remove(K cle) {
        Maillon m = (Maillon) barrette.remove(cle);
        if (m!=null) {
            if (disposer!=null) disposer.dispose(m.contenu);
            m.contenu = null;
            m.precedent.suivant = m.suivant;
            m.suivant.precedent = m.precedent;
            fond.suivant = m;
            m.precedent = fond;
            fond = m;
        }
    }


    public synchronized Object put(K cle, T valeur) {
        if (cle==null) return valeur;

        if (fond.cle!=null) {
            barrette.remove(fond.cle);
            if (disposer!=null) disposer.dispose(fond.contenu);
        }
        fond.cle = cle;
        barrette.put(cle, fond);
        fond.contenu = valeur;
        fond.suivant = sommet;
        sommet.precedent = fond;
        sommet = fond;
        fond = fond.precedent;
        fond.suivant = null;

        return valeur;
    }

    public int computeDepth(K cle) {
        Maillon m = sommet;
        for (int i=0; i<tailleCache; i++) {
            if (cle.equals(m.cle)) return i;
            m=m.suivant;
            if (m==null) {
                break;
            }
        }
        return -1;
    }

    @SuppressWarnings("unchecked")
    public synchronized void removeAll() {
        if (disposer!=null) {
            for (Maillon m : barrette.values()) {
                disposer.dispose(m.contenu);
            }
        }
        barrette = new HashMap<K, Maillon>();
        Maillon[] t = new HashCache.Maillon[tailleCache];
        sommet = t[0] = new Maillon();
        for (int i=1; i<tailleCache; i++) (t[i-1].suivant = t[i] = new Maillon()).precedent = t[i-1];
        fond = t[tailleCache-1];
    }


    public synchronized T get(K cle) {
        Maillon m = barrette.get(cle);
        if (m == sommet) return m.contenu;
        if (m == null) return null;
        if (m == fond) {
            m.precedent.suivant = null;
            m.suivant = sommet;
            sommet.precedent = m;
            sommet = m;
            fond = m.precedent;
            m.precedent = null;
        } else {
            m.suivant.precedent = m.precedent;
            m.precedent.suivant = m.suivant;
            m.suivant = sommet;
            sommet.precedent = m;
            sommet = m;
        }
        return m.contenu;
    }

    public Disposer<T> getDisposer() {
        return disposer;
    }

    public void setDisposer(Disposer<T> disposer) {
        this.disposer = disposer;
    }

}

回答by Brian Agnew

If this isn'thomework, I would strongly recommend using a third-party library to avoid the pain of designing, testing and maintaining your own solutuion.

如果这不是家庭作业,我强烈建议使用第三方库以避免设计、测试和维护自己的解决方案的痛苦。

See the Guava MapMakermechanism, for example.

例如,参见Guava MapMaker机制。