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
How to limit the maximum size of a Map by removing oldest entries when limit reached
提问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机制。