Как реализовать простое кэширование в Java?

«Как реализовать простое кэширование в Java?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Самый простой способ — использовать HashMap для хранения данных в памяти.

public class SimpleCache<K, V> {
    private final Map<K, V> cache = new HashMap<>();

    public void put(K key, V value) {
        cache.put(key, value);
    }

    public V get(K key) {
        return cache.get(key);
    }

    public void remove(K key) {
        cache.remove(key);
    }
}

Почему это просто, но не всегда достаточно:

  • Плюсы: Минимальная реализация, быстрый доступ O(1).
  • Минусы:
    • Нет ограничения размера (риск OutOfMemoryError).
    • Нет политики вытеснения (например, LRU).
    • Нет TTL (Time-To-Live) для устаревания записей.
    • Не потокобезопасно для HashMap.

Практические улучшения:

  1. Для потокобезопасности используйте ConcurrentHashMap.
  2. Для production-систем применяйте специализированные библиотеки:
    • Caffeine: Высокопроизводительный, современный кэш.
    • Guava Cache: От Google, богатый API (размер, TTL, статистика).

Пример с ConcurrentHashMap и LRU-подобным поведением:

public class SimpleConcurrentCache<K, V> {
    private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
    private final int maxSize;
    private final LinkedBlockingQueue<K> order = new LinkedBlockingQueue<>();

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

    public void put(K key, V value) {
        if (cache.size() >= maxSize) {
            K oldestKey = order.poll(); // Удаляем самый старый ключ
            if (oldestKey != null) cache.remove(oldestKey);
        }
        cache.put(key, value);
        order.offer(key);
    }
    // ... get, remove
}