LRUCache.java

package com.renomad.minum.utils;

import java.io.Serial;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * A simple Least-Recently Used Cache
 * See <a href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)">LRU</a>
 */
public final class LRUCache<K,V> extends LinkedHashMap<K, V> {

    @Serial
    private static final long serialVersionUID = -8687744696157499778L;

    // max number of entries allowed in this cache
    private static final int DEFAULT_MAX_ENTRIES = 100;
    private final int maxSize;

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

    private LRUCache(int maxSize) {
        // uses the same load factor as found in java.util.Hashmap.DEFAULT_LOAD_FACTOR
        super(maxSize + 1, 0.75f, true);
        this.maxSize = maxSize;
    }

    /**
     * Builds a map that functions as a least-recently used cache.
     * Sets the max size to DEFAULT_MAX_ENTRIES. If you want to specify the max size,
     * use the constructor at {@link #getLruCache(int)}
     * <br>
     * Make sure, when using this, to assign it to a fully-defined
     * type, e.g. {@code Map<String, String> foo = getLruCache()}
     * This is necessary since we provide this as a generic method,
     * and the assignment is what enables Java to determine
     * what types to build.
     */
    public static <K,V> Map<K, V> getLruCache() {
        return getLruCache(DEFAULT_MAX_ENTRIES);
    }

    /**
     * Creates an LRUCache, allowing you to specify the max size.
     * Alternately, see {@link #getLruCache()}.
     * <br>
     * Make sure, when using this, to assign it to a fully-defined
     * type, e.g. {@code Map<String, String> foo = getLruCache(2)}
     * This is necessary since we provide this as a generic method,
     * and the assignment is what enables Java to determine
     * what types to build.
     */
    public static <K,V> Map<K, V> getLruCache(int maxSize) {
        return new LRUCache<>(maxSize);
    }
}