I have a hashmap in Java that I need to limit in size (order of 50000). But I should delete only items that are the oldest. The timestamp of the item is stored in the entry object's field:
Map<String, MyModel> snapshot = new HashMap<>();
and
public class MyModel {
private ZonedDateTime createdAt;
// other fields...
}
I also insert them into the map in order by that timestamp.
What would be the most effective way to accomplish this kind of deletion of oldest entries? Note that "threshold" in time is not known, only the desired final size of the Map.
The Java HashMap remove() method removes the mapping from the hashmap associated with the specified key. The syntax of the remove() method is: hashmap. remove(Object key, Object value);
While iterating, check for the key at that iteration to be equal to the key specified. The entry key of the Map can be obtained with the help of entry. getKey() method. If the key matches, remove the entry of that iteration from the HashMap using remove() method.
It is not allowed to modify a map in Java while iterating over it to avoid non-deterministic behavior at a later stage. For example, the following code example throws a java. util. ConcurrentModificationException since the remove() method of the Map interface is called during iteration.
clear() method in Java is used to clear and remove all the elements or mappings from a specified HashMap.
HashMap
has no "oldest", it has no "first", it has no order.
A LinkedHashMap
on the other hand is designed for exactly this, it maintains a doubly linked list between the entries so keep them in insertion order, it also provides a removeEldestEntry
method:
public static void main(final String args[]) throws Exception {
final int maxSize = 4;
final LinkedHashMap<String, String> cache = new LinkedHashMap<String, String>() {
@Override
protected boolean removeEldestEntry(final Map.Entry eldest) {
return size() > maxSize;
}
};
cache.put("A", "A");
System.out.println(cache);
cache.put("B", "A");
System.out.println(cache);
cache.put("C", "A");
System.out.println(cache);
cache.put("D", "A");
System.out.println(cache);
cache.put("E", "A");
System.out.println(cache);
cache.put("F", "A");
System.out.println(cache);
cache.put("G", "A");
}
Output:
{A=A}
{A=A, B=A}
{A=A, B=A, C=A}
{A=A, B=A, C=A, D=A}
{B=A, C=A, D=A, E=A}
{C=A, D=A, E=A, F=A}
Note that this implementation is not
synchronized
. If multiple threads access a linked hash map concurrently, and at least one of the threads modifies the map structurally, it must besynchronized
externally. This is typically accomplished bysynchronizing
on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using theCollections.synchronizedMap
method. This is best done at creation time, to prevent accidental unsynchronized access to the map:
Map m = Collections.synchronizedMap(new LinkedHashMap(...));
LinkedHashMap
JavaDoc
It may be easiest just to add the String objects to a list whenever you put something in the map. Then you could do:
while(map.size()>50000){
map.remove(list.get(0))
list.remove(0);
}
This works because you don't actually care about the time, just the order.
A queue would be better than a list in this regard as you don't need anything other than accessing and removing the first element
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With