4
4
import java .util .Map ;
5
5
6
6
/**
7
- * Most recently used (MRU)
7
+ * Represents a Most Recently Used (MRU) Cache.
8
8
* <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.
12
12
*
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
15
18
*/
16
19
public class MRUCache <K , V > {
17
20
@@ -21,40 +24,74 @@ public class MRUCache<K, V> {
21
24
private int cap ;
22
25
private static final int DEFAULT_CAP = 100 ;
23
26
27
+ /**
28
+ * Creates an MRUCache with the default capacity.
29
+ */
24
30
public MRUCache () {
25
31
setCapacity (DEFAULT_CAP );
26
32
}
27
33
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
+ */
28
49
private void setCapacity (int newCapacity ) {
29
50
checkCapacity (newCapacity );
30
- for ( int i = data .size (); i > newCapacity ; i -- ) {
51
+ while ( data .size () > newCapacity ) {
31
52
Entry <K , V > evicted = evict ();
32
53
data .remove (evicted .getKey ());
33
54
}
34
55
this .cap = newCapacity ;
35
56
}
36
57
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
+ */
37
64
private void checkCapacity (int capacity ) {
38
65
if (capacity <= 0 ) {
39
- throw new RuntimeException ( "capacity must greater than 0!" );
66
+ throw new IllegalArgumentException ( "Capacity must be greater than 0!" );
40
67
}
41
68
}
42
69
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
+ */
43
76
private Entry <K , V > evict () {
44
77
if (head == null ) {
45
- throw new RuntimeException ("cache cannot be empty!" );
78
+ throw new RuntimeException ("Cache cannot be empty!" );
46
79
}
47
80
final Entry <K , V > evicted = this .tail ;
48
81
tail = evicted .getPreEntry ();
49
- tail .setNextEntry (null );
82
+ if (tail != null ) {
83
+ tail .setNextEntry (null );
84
+ }
50
85
evicted .setNextEntry (null );
51
86
return evicted ;
52
87
}
53
88
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
+ */
58
95
public V get (K key ) {
59
96
if (!data .containsKey (key )) {
60
97
return null ;
@@ -64,11 +101,19 @@ public V get(K key) {
64
101
return entry .getValue ();
65
102
}
66
103
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
+ */
67
112
public void put (K key , V value ) {
68
113
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 );
72
117
return ;
73
118
}
74
119
Entry <K , V > newEntry ;
@@ -84,6 +129,11 @@ public void put(K key, V value) {
84
129
data .put (key , newEntry );
85
130
}
86
131
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
+ */
87
137
private void addNewEntry (Entry <K , V > newEntry ) {
88
138
if (data .isEmpty ()) {
89
139
head = newEntry ;
@@ -96,6 +146,11 @@ private void addNewEntry(Entry<K, V> newEntry) {
96
146
tail = newEntry ;
97
147
}
98
148
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
+ */
99
154
private void moveEntryToLast (Entry <K , V > entry ) {
100
155
if (tail == entry ) {
101
156
return ;
@@ -117,8 +172,14 @@ private void moveEntryToLast(Entry<K, V> entry) {
117
172
tail = entry ;
118
173
}
119
174
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
+ */
120
182
static final class Entry <I , J > {
121
-
122
183
private Entry <I , J > preEntry ;
123
184
private Entry <I , J > nextEntry ;
124
185
private I key ;
0 commit comments