web-dev-qa-db-fra.com

Limiter la taille maximale d'un HashMap dans Java

Je souhaite limiter la taille maximale d'un HashMap pour prendre des mesures sur une variété d'algorithmes de hachage que j'implémente. J'ai regardé le facteur de charge dans l'un des constructeurs surchargés de HashMap.

HashMap(int initialCapacity, float loadFactor) 

J'ai essayé de définir le loadFactor à 0.0f dans le constructeur (ce qui signifie que je ne veux pas que le HashMap grandisse) mais javac appelle cela invalide:

Exception in thread "main" Java.lang.IllegalArgumentException: Illegal load factor: 0.0
        at Java.util.HashMap.<init>(HashMap.Java:177)
        at hashtables.CustomHash.<init>(Main.Java:20)
        at hashtables.Main.main(Main.Java:70) Java Result: 1

Existe-t-il un autre moyen de limiter la taille de HashMap pour qu'elle ne croisse jamais?

31
andandandand

Parfois plus simple, c'est mieux.

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

    private Map<K, V> map;

    public InstrumentedHashMap() {
        map = new HashMap<K, V>();
    }

    public boolean put(K key, V value) {
        if (map.size() >= MAX && !map.containsKey(key)) {
             return false;
        } else {
             map.put(key, value);
             return true;
        }
    }

    ...
}
36
Mike

Vous pouvez créer une nouvelle classe comme celle-ci pour limiter la taille d'un HashMap:

public class MaxSizeHashMap<K, V> extends LinkedHashMap<K, V> {
    private final int maxSize;

    public MaxSizeHashMap(int maxSize) {
        this.maxSize = maxSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > maxSize;
    }
}
115
WhiteFang34

Une solution simple est généralement la meilleure, alors utilisez non modifiable ou immuable hashmap.

Si vous ne pouvez pas modifier la quantité d'éléments, la taille sera corrigée - problème résolu.

6
Margus
public class Cache {
    private LinkedHashMap<String, String> Cache = null;
    private final int cacheSize;  
    private ReadWriteLock readWriteLock=null;
    public Cache(LinkedHashMap<String, String> psCacheMap, int size) {
        this.Cache = psCacheMap;
        cacheSize = size;
        readWriteLock=new ReentrantReadWriteLock();
    }

    public void put(String sql, String pstmt) throws SQLException{
        if(Cache.size() >= cacheSize && cacheSize > 0){
            String oldStmt=null;
            String oldSql = Cache.keySet().iterator().next();
            oldStmt = remove(oldSql);
            oldStmt.inCache(false);
            oldStmt.close();

        }
        Cache.put(sql, pstmt);
    }

    public String get(String sql){
        Lock readLock=readWriteLock.readLock();
        try{
            readLock.lock();
            return Cache.get(sql);
        }finally{
            readLock.unlock();
        }
    }

    public boolean containsKey(String sql){
        Lock readLock=readWriteLock.readLock();
        try{
            readLock.lock();
            return Cache.containsKey(sql);
        }finally{
            readLock.unlock();
        }
    }

    public String remove(String key){
        Lock writeLock=readWriteLock.writeLock();
        try{
            writeLock.lock();
            return Cache.remove(key);
        }finally{
            writeLock.unlock();
        }
    }

    public LinkedHashMap<String, String> getCache() {
        return Cache;
    }

    public void setCache(
            LinkedHashMap<String, String> Cache) {
        this.Cache = Cache;
    }


}
2
Kanagavelu Sugumar

La méthode put de la classe HashMap est celle en charge de l'ajout des éléments dans le HashMap et elle le fait en appelant une méthode nommée addEntry dont le code est le suivant:

   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);
    } 

Comme vous pouvez le voir dans cette méthode, c'est là que le HashMap est redimensionné si le seuil a été dépassé, donc j'essayerais d'étendre la classe HashMap et d'écrire mes propres méthodes pour put et addEntry afin de supprimer le redimensionnement. Quelque chose comme:

package Java.util;

public class MyHashMap<K, V> extends HashMap {


    private V myPutForNullKey(V value) {
        for (Entry<K, V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        myAddEntry(0, null, value, 0);
        return null;
    }

    public V myPut(K key, V value) {
        if (key == null)
            return myPutForNullKey(value);
        if (size < table.length) { 
            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++;
            myAddEntry(hash, key, value, i);
        }
        return null;
    }

    void myAddEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K, V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
        size++;
    }
}

Vous auriez besoin d'écrire vos propres méthodes car put et addEntry ne peuvent pas être redéfinies et vous devriez également faire de même pour putForNullKey car elle est appelée à l'intérieur put. Une validation dans put est requise pour vérifier que nous n'essayons pas de mettre un objet si la table est pleine.

1
Maricel