{"record":{"id":"afadcffd6f7914db","repo":"TheAlgorithms/Java","slug":"key-and-value-must-not-be-null-afadcf","errorCode":null,"errorMessage":"Key and value must not be null","messagePattern":"Key and value must not be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java","lineNumber":172,"sourceCode":"        put(key, value, defaultTTL);\n    }\n\n    /**\n     * Adds a key-value pair to the cache with a specified time-to-live (TTL).\n     *\n     * <p>If the key already exists, its value is removed, re-inserted at tail and its TTL is reset.\n     * If the key does not exist and the cache is full, the youngest entry is evicted to make space.\n     * Expired entries are also cleaned up prior to any eviction. The eviction listener\n     * is notified when an entry gets evicted.\n     *\n     * @param key        the key to associate with the cached value; must not be {@code null}\n     * @param value      the value to be cached; must not be {@code null}\n     * @param ttlMillis  the time-to-live for this entry in milliseconds; must be >= 0\n     * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative\n     */\n    public void put(K key, V value, long ttlMillis) {\n        if (key == null || value == null) {\n            throw new IllegalArgumentException(\"Key and value must not be null\");\n        }\n        if (ttlMillis < 0) {\n            throw new IllegalArgumentException(\"TTL must be >= 0\");\n        }\n\n        lock.lock();\n        try {\n            // If key already exists, remove it. It will later be re-inserted at top of stack\n            keys.remove(key);\n            final CacheEntry<V> oldEntry = cache.remove(key);\n            if (oldEntry != null && !oldEntry.isExpired()) {\n                notifyEviction(key, oldEntry.value);\n            }\n\n            // Evict expired entries to make space for new entry\n            evictExpired();\n\n            // If no expired entry was removed, remove the youngest","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/TheAlgorithms/Java/blob/fdfb9a395b310167a66bd29e311e36e0e3e9b964/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java#L154-L190","documentation":"Thrown by LIFOCache.put(K, V, long) when either the key or the value is null. The cache maintains both a HashMap and an insertion-order stack (keys), and a null value would be ambiguous with absent/expired entries while a null key would break both structures. The check runs before lock acquisition and before TTL validation.","triggerScenarios":"cache.put(key, null, ttl); cache.put(null, value, ttl); caching a computation result that is null; DTO fields defaulting to null.","commonSituations":"Caching repository lookups that legitimately return absent; test fixtures missing a field; ORM mappings yielding null.","solutions":["Skip caching when the value is null: if (value != null) cache.put(key, value, ttl);","Represent absence with a sentinel or Optional.","Validate key and value at the service boundary."],"exampleFix":"// before\ncache.put(id, repo.find(id), ttl);\n// after\nV value = repo.find(id);\nif (id != null && value != null) cache.put(id, value, ttl);","handlingStrategy":"validation","validationCode":"if (key == null || value == null) {\n    return;\n}\ncache.put(key, value, ttlMillis);","typeGuard":"static <K, V> boolean isCacheable(K key, V value) {\n    return key != null && value != null;\n}","tryCatchPattern":null,"preventionTips":["Treat a null computed value as 'do not cache'.","Use a sentinel or Optional for absence.","Validate both key and value at the service boundary."],"tags":["java","lifo-cache","null-check","argument-validation","cache"],"backgroundTag":null,"analyzedSha":"fdfb9a395b310167a66bd29e311e36e0e3e9b964","analyzedAt":"2026-08-13T23:36:13.315Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}