44import java .util .Map ;
55
66/**
7- * Most recently used (MRU)
7+ * Represents a Most Recently Used (MRU) Cache.
88 * <p>
9- * In contrast to Least Recently Used (LRU), MRU discards the most recently used
10- * items first.
11- * https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)
9+ * In contrast to the Least Recently Used (LRU) strategy, the MRU caching policy
10+ * evicts the most recently accessed items first. This class provides methods to
11+ * store key-value pairs and manage cache eviction based on this policy.
1212 *
13- * @param <K> key type
14- * @param <V> value type
13+ * For more information, refer to:
14+ * <a href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)">MRU on Wikipedia</a>.
15+ *
16+ * @param <K> the type of keys maintained by this cache
17+ * @param <V> the type of values associated with the keys
1518 */
1619public class MRUCache <K , V > {
1720
@@ -21,40 +24,74 @@ public class MRUCache<K, V> {
2124 private int cap ;
2225 private static final int DEFAULT_CAP = 100 ;
2326
27+ /**
28+ * Creates an MRUCache with the default capacity.
29+ */
2430 public MRUCache () {
2531 setCapacity (DEFAULT_CAP );
2632 }
2733
34+ /**
35+ * Creates an MRUCache with a specified capacity.
36+ *
37+ * @param cap the maximum number of items the cache can hold
38+ */
39+ public MRUCache (int cap ) {
40+ setCapacity (cap );
41+ }
42+
43+ /**
44+ * Sets the capacity of the cache and evicts items if the new capacity
45+ * is less than the current number of items.
46+ *
47+ * @param newCapacity the new capacity to set
48+ */
2849 private void setCapacity (int newCapacity ) {
2950 checkCapacity (newCapacity );
30- for ( int i = data .size (); i > newCapacity ; i -- ) {
51+ while ( data .size () > newCapacity ) {
3152 Entry <K , V > evicted = evict ();
3253 data .remove (evicted .getKey ());
3354 }
3455 this .cap = newCapacity ;
3556 }
3657
58+ /**
59+ * Checks if the specified capacity is valid.
60+ *
61+ * @param capacity the capacity to check
62+ * @throws IllegalArgumentException if the capacity is less than or equal to zero
63+ */
3764 private void checkCapacity (int capacity ) {
3865 if (capacity <= 0 ) {
39- throw new RuntimeException ( "capacity must greater than 0!" );
66+ throw new IllegalArgumentException ( "Capacity must be greater than 0!" );
4067 }
4168 }
4269
70+ /**
71+ * Evicts the most recently used entry from the cache.
72+ *
73+ * @return the evicted entry
74+ * @throws RuntimeException if the cache is empty
75+ */
4376 private Entry <K , V > evict () {
4477 if (head == null ) {
45- throw new RuntimeException ("cache cannot be empty!" );
78+ throw new RuntimeException ("Cache cannot be empty!" );
4679 }
4780 final Entry <K , V > evicted = this .tail ;
4881 tail = evicted .getPreEntry ();
49- tail .setNextEntry (null );
82+ if (tail != null ) {
83+ tail .setNextEntry (null );
84+ }
5085 evicted .setNextEntry (null );
5186 return evicted ;
5287 }
5388
54- public MRUCache (int cap ) {
55- setCapacity (cap );
56- }
57-
89+ /**
90+ * Retrieves the value associated with the specified key.
91+ *
92+ * @param key the key whose associated value is to be returned
93+ * @return the value associated with the specified key, or null if the key does not exist
94+ */
5895 public V get (K key ) {
5996 if (!data .containsKey (key )) {
6097 return null ;
@@ -64,11 +101,19 @@ public V get(K key) {
64101 return entry .getValue ();
65102 }
66103
104+ /**
105+ * Associates the specified value with the specified key in the cache.
106+ * If the key already exists, its value is updated and the entry is moved to the most recently used position.
107+ * If the cache is full, the most recently used entry is evicted before adding the new entry.
108+ *
109+ * @param key the key with which the specified value is to be associated
110+ * @param value the value to be associated with the specified key
111+ */
67112 public void put (K key , V value ) {
68113 if (data .containsKey (key )) {
69- final Entry <K , V > exitingEntry = data .get (key );
70- exitingEntry .setValue (value );
71- moveEntryToLast (exitingEntry );
114+ final Entry <K , V > existingEntry = data .get (key );
115+ existingEntry .setValue (value );
116+ moveEntryToLast (existingEntry );
72117 return ;
73118 }
74119 Entry <K , V > newEntry ;
@@ -84,6 +129,11 @@ public void put(K key, V value) {
84129 data .put (key , newEntry );
85130 }
86131
132+ /**
133+ * Adds a new entry to the cache and updates the head and tail pointers accordingly.
134+ *
135+ * @param newEntry the new entry to be added
136+ */
87137 private void addNewEntry (Entry <K , V > newEntry ) {
88138 if (data .isEmpty ()) {
89139 head = newEntry ;
@@ -96,6 +146,11 @@ private void addNewEntry(Entry<K, V> newEntry) {
96146 tail = newEntry ;
97147 }
98148
149+ /**
150+ * Moves the specified entry to the most recently used position in the cache.
151+ *
152+ * @param entry the entry to be moved
153+ */
99154 private void moveEntryToLast (Entry <K , V > entry ) {
100155 if (tail == entry ) {
101156 return ;
@@ -117,8 +172,14 @@ private void moveEntryToLast(Entry<K, V> entry) {
117172 tail = entry ;
118173 }
119174
175+ /**
176+ * A nested class representing an entry in the cache, which holds a key-value pair
177+ * and references to the previous and next entries in the linked list structure.
178+ *
179+ * @param <I> the type of the key
180+ * @param <J> the type of the value
181+ */
120182 static final class Entry <I , J > {
121-
122183 private Entry <I , J > preEntry ;
123184 private Entry <I , J > nextEntry ;
124185 private I key ;
0 commit comments