From 5466ff0d577883e3fcb27b3feddad141d20b6355 Mon Sep 17 00:00:00 2001 From: varnaa Date: Sun, 2 Aug 2020 22:20:39 +0530 Subject: [PATCH] Added LRU cache implementation. --- src/main/java/com/caching/LRUCache.java | 93 +++++++++++++++++++++ src/test/java/com/caching/LRUCacheTest.java | 25 ++++++ 2 files changed, 118 insertions(+) create mode 100644 src/main/java/com/caching/LRUCache.java create mode 100644 src/test/java/com/caching/LRUCacheTest.java diff --git a/src/main/java/com/caching/LRUCache.java b/src/main/java/com/caching/LRUCache.java new file mode 100644 index 00000000..e043e35d --- /dev/null +++ b/src/main/java/com/caching/LRUCache.java @@ -0,0 +1,93 @@ +package com.caching; + + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NoSuchElementException; + +/** + * Your LRUCache can be instantiated and called as such: + * LRUCache lruCache = new LRUCache(capacity); + * lruCache.put(key,value); + * int param_1 = lruCache.get(key); + */ + +public class LRUCache { + /** + * The class LinkedHashMap,is a subclass of HashMap that preserves the insertion order. + * We can take advantage of this class to avoid having to implement the linked list. + * A special constructor is provided to create a linked hash map whose order of + * iteration is the order in which its entries were least-recently (access-order). + */ + private final LinkedHashMap cache; + private final int capacity; + + /** + * @param capacity - Instantiates LRUCache with the given capacity. + */ + public LRUCache(int capacity) { + this.capacity = capacity; + + /* + @param loadFactor Load Factor is a measure, which decides when exactly to resize the + * HashMap. By default capacity = 16 and loadFactor = 0.75f. This means + * that reisze when HashMap reaches 75% of its capacity. For we will + * remove an element only if the cache reaches 100% capacity (1.0f). + * + * @param accessOrder - Set to true if ordering mode is specified (removeEldestEntry). + */ + this.cache = new LinkedHashMap<>(capacity, 1.0f, true) { + /** + * @param eldest - The least recently accessed entry This is the entry that will + * be removed if the method returns {@code true}. + * returns {@code false} if it should be retained. + */ + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return this.size() > capacity; + } + }; + } + + + /** + * To put a value in LRU cache with corresponding key + * We add the value for key only if the key is not present. + * We don't update existing values, only access-order is updated. + * + * @param key The key (int) + * @param value The value to be cached + */ + public void put(int key, T value) { + if (capacity == 0) { + System.out.println("Cache set to 0 capacity. No elements will be cached"); + } + + T currentValue = cache.get(key); + if (!cache.containsKey(key)) { + cache.put(key, value); + System.out.println("Adding new key:" + key + " to cache"); + } else { + System.out.println("Key:" + key + " already present in cache. Access order will be updated."); + } + } + + + /** + * To get the cached value for given key + * + * @param key The key (int) of the expected value + * @return corresponding value for input key + * @throws NoSuchElementException if key is absent + */ + public T get(int key) { + // cache hit condition + if (cache.containsKey(key)) { + T value = cache.get(key); + System.out.println("Returning value from cache:" + value); + return value; + } + // cache miss condition + throw new NoSuchElementException("No element found for key:" + key); + } +} diff --git a/src/test/java/com/caching/LRUCacheTest.java b/src/test/java/com/caching/LRUCacheTest.java new file mode 100644 index 00000000..78c3f45f --- /dev/null +++ b/src/test/java/com/caching/LRUCacheTest.java @@ -0,0 +1,25 @@ +package com.caching; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; + +public class LRUCacheTest { + + @Test + public void testLFUCache() { + LRUCache cache = new LRUCache(2); + + cache.put(1, 5); + cache.put(2, 4); + Assertions.assertEquals(5, cache.get(1)); // returns 5 + cache.put(3, 6); // evicts key 2 + Assertions.assertThrows(NoSuchElementException.class, () -> cache.get(7));// throws exception + Assertions.assertEquals(6, cache.get(3)); // returns 6. + cache.put(4, 8); // evicts key 1. + Assertions.assertThrows(NoSuchElementException.class, () -> cache.get(1));// throws exception + Assertions.assertEquals(6, cache.get(3)); // returns 6 + Assertions.assertEquals(8, cache.get(4)); // returns 8 + } +} \ No newline at end of file