Class LRUMap<K,V>

Type Parameters:
K - the type of the keys in this map
V - the type of the values in this map
All Implemented Interfaces:
Serializable, Cloneable, Map<K,V>, BoundedMap<K,V>, Get<K,V>, IterableGet<K,V>, IterableMap<K,V>, OrderedMap<K,V>, Put<K,V>

public class LRUMap<K,V> extends AbstractLinkedMap<K,V> implements BoundedMap<K,V>, Serializable, Cloneable
A Map implementation with a fixed maximum size which removes the least recently used entry if an entry is added when full.

The least recently used algorithm works on the get and put operations only. Iteration of any kind, including setting the value by iteration, does not change the order. Queries such as containsKey and containsValue or access via views also do not change the order.

A somewhat subtle ramification of the least recently used algorithm is that calls to get(Object) stand a very good chance of modifying the map's iteration order and thus invalidating any iterators currently in use. It is therefore suggested that iterations over an LRUMap instance access entry values only through a MapIterator or AbstractHashedMap.entrySet() iterator.

The map implements OrderedMap and entries may be queried using the bidirectional OrderedMapIterator. The order returned is least recently used to most recently used. Iterators from map views can also be cast to OrderedIterator if required.

All the available iterators can be reset back to the start by casting to ResettableIterator and calling reset().

Note that LRUMap is not synchronized and is not thread-safe. If you wish to use this map from multiple threads concurrently, you must use appropriate synchronization. The simplest approach is to wrap this map using Collections.synchronizedMap(Map). This class may throw NullPointerException's when accessed by concurrent threads.

Since:
3.0 (previously in main package v1.0)
See Also:
  • Field Details

  • Constructor Details

    • LRUMap

      public LRUMap()
      Constructs a new empty map with a maximum size of 100.
    • LRUMap

      public LRUMap(int maxSize)
      Constructs a new, empty map with the specified maximum size.
      Parameters:
      maxSize - the maximum size of the map
      Throws:
      IllegalArgumentException - if the maximum size is less than one
    • LRUMap

      public LRUMap(int maxSize, boolean scanUntilRemovable)
      Constructs a new, empty map with the specified maximum size.
      Parameters:
      maxSize - the maximum size of the map
      scanUntilRemovable - scan until a removable entry is found, default false
      Throws:
      IllegalArgumentException - if the maximum size is less than one
      Since:
      3.1
    • LRUMap

      public LRUMap(int maxSize, float loadFactor)
      Constructs a new, empty map with the specified max capacity and load factor.
      Parameters:
      maxSize - the maximum size of the map
      loadFactor - the load factor
      Throws:
      IllegalArgumentException - if the maximum size is less than one
      IllegalArgumentException - if the load factor is less than zero
    • LRUMap

      public LRUMap(int maxSize, float loadFactor, boolean scanUntilRemovable)
      Constructs a new, empty map with the specified max capacity and load factor.
      Parameters:
      maxSize - the maximum size of the map
      loadFactor - the load factor
      scanUntilRemovable - scan until a removable entry is found, default false
      Throws:
      IllegalArgumentException - if the maximum size is less than one
      IllegalArgumentException - if the load factor is less than zero
      Since:
      3.1
    • LRUMap

      public LRUMap(int maxSize, int initialSize)
      Constructs a new, empty map with the specified maximum size.
      Parameters:
      maxSize - the maximum size of the map
      initialSize - the initial size of the map
      Throws:
      IllegalArgumentException - if the maximum size is less than one
      IllegalArgumentException - if the initial size is negative or larger than the maximum size
      Since:
      4.1
    • LRUMap

      public LRUMap(int maxSize, int initialSize, float loadFactor)
      Constructs a new, empty map with the specified max / initial capacity and load factor.
      Parameters:
      maxSize - the maximum size of the map
      initialSize - the initial size of the map
      loadFactor - the load factor
      Throws:
      IllegalArgumentException - if the maximum size is less than one
      IllegalArgumentException - if the initial size is negative or larger than the maximum size
      IllegalArgumentException - if the load factor is less than zero
      Since:
      4.1
    • LRUMap

      public LRUMap(int maxSize, int initialSize, float loadFactor, boolean scanUntilRemovable)
      Constructs a new, empty map with the specified max / initial capacity and load factor.
      Parameters:
      maxSize - the maximum size of the map
      initialSize - the initial size of the map
      loadFactor - the load factor
      scanUntilRemovable - scan until a removable entry is found, default false
      Throws:
      IllegalArgumentException - if the maximum size is less than one
      IllegalArgumentException - if the initial size is negative or larger than the maximum size
      IllegalArgumentException - if the load factor is less than zero
      Since:
      4.1
    • LRUMap

      public LRUMap(Map<? extends K,? extends V> map)
      Constructor copying elements from another map.

      The maximum size is set from the map's size.

      Parameters:
      map - the map to copy
      Throws:
      NullPointerException - if the map is null
      IllegalArgumentException - if the map is empty
    • LRUMap

      public LRUMap(Map<? extends K,? extends V> map, boolean scanUntilRemovable)
      Constructor copying elements from another map.

      The maximum size is set from the map's size.

      Parameters:
      map - the map to copy
      scanUntilRemovable - scan until a removable entry is found, default false
      Throws:
      NullPointerException - if the map is null
      IllegalArgumentException - if the map is empty
      Since:
      3.1
  • Method Details

    • addMapping

      protected void addMapping(int hashIndex, int hashCode, K key, V value)
      Adds a new key-value mapping into this map.

      This implementation checks the LRU size and determines whether to discard an entry or not using removeLRU(AbstractLinkedMap.LinkEntry).

      From Commons Collections 3.1 this method uses isFull() rather than accessing size and maxSize directly. It also handles the scanUntilRemovable functionality.

      Overrides:
      addMapping in class AbstractHashedMap<K,V>
      Parameters:
      hashIndex - the index into the data array to store at
      hashCode - the hash code of the key to add
      key - the key to add
      value - the value to add
    • clone

      public LRUMap<K,V> clone()
      Clones the map without cloning the keys or values.
      Overrides:
      clone in class AbstractHashedMap<K,V>
      Returns:
      a shallow clone
    • doReadObject

      Reads the data necessary for put() to work in the superclass.
      Overrides:
      doReadObject in class AbstractHashedMap<K,V>
      Parameters:
      in - the input stream
      Throws:
      IOException - if an error occurs while reading from the stream
      ClassNotFoundException - if an object read from the stream can not be loaded
    • doWriteObject

      protected void doWriteObject(ObjectOutputStream out) throws IOException
      Writes the data necessary for put() to work in deserialization.
      Overrides:
      doWriteObject in class AbstractHashedMap<K,V>
      Parameters:
      out - the output stream
      Throws:
      IOException - if an error occurs while writing to the stream
    • get

      public V get(Object key)
      Gets the value mapped to the key specified.

      This operation changes the position of the key in the map to the most recently used position (last).

      Specified by:
      get in interface Get<K,V>
      Specified by:
      get in interface Map<K,V>
      Overrides:
      get in class AbstractHashedMap<K,V>
      Parameters:
      key - the key
      Returns:
      the mapped value, null if no match
      See Also:
    • get

      public V get(Object key, boolean updateToMRU)
      Gets the value mapped to the key specified.

      If updateToMRU is true, the position of the key in the map is changed to the most recently used position (last), otherwise the iteration order is not changed by this operation.

      Parameters:
      key - the key
      updateToMRU - whether the key shall be updated to the most recently used position
      Returns:
      the mapped value, null if no match
      Since:
      4.1
    • isFull

      public boolean isFull()
      Returns true if this map is full and no new mappings can be added.
      Specified by:
      isFull in interface BoundedMap<K,V>
      Returns:
      true if the map is full
    • isScanUntilRemovable

      public boolean isScanUntilRemovable()
      Whether this LRUMap will scan until a removable entry is found when the map is full.
      Returns:
      true if this map scans
      Since:
      3.1
    • maxSize

      public int maxSize()
      Gets the maximum size of the map (the bound).
      Specified by:
      maxSize in interface BoundedMap<K,V>
      Returns:
      the maximum number of elements the map can hold
    • moveToMRU

      protected void moveToMRU(AbstractLinkedMap.LinkEntry<K,V> entry)
      Moves an entry to the MRU position at the end of the list.

      This implementation moves the updated entry to the end of the list.

      Parameters:
      entry - the entry to update
    • removeLRU

      protected boolean removeLRU(AbstractLinkedMap.LinkEntry<K,V> entry)
      Subclass method to control removal of the least recently used entry from the map.

      This method exists for subclasses to override. A subclass may wish to provide cleanup of resources when an entry is removed. For example:

       protected boolean removeLRU(LinkEntry entry) {
         releaseResources(entry.getValue());  // release resources held by entry
         return true;  // actually delete entry
       }
       

      Alternatively, a subclass may choose to not remove the entry or selectively keep certain LRU entries. For example:

       protected boolean removeLRU(LinkEntry entry) {
         if (entry.getKey().toString().startsWith("System.")) {
           return false;  // entry not removed from LRUMap
         } else {
           return true;  // actually delete entry
         }
       }
       
      The effect of returning false is dependent on the scanUntilRemovable flag. If the flag is true, the next LRU entry will be passed to this method and so on until one returns false and is removed, or every entry in the map has been passed. If the scanUntilRemovable flag is false, the map will exceed the maximum size.

      NOTE: Commons Collections 3.0 passed the wrong entry to this method. This is fixed in version 3.1 onwards.

      Parameters:
      entry - the entry to be removed
      Returns:
      true
    • reuseMapping

      protected void reuseMapping(AbstractLinkedMap.LinkEntry<K,V> entry, int hashIndex, int hashCode, K key, V value)
      Parameters:
      entry - the entry to reuse
      hashIndex - the index into the data array to store at
      hashCode - the hash code of the key to add
      key - the key to add
      value - the value to add
    • updateEntry

      protected void updateEntry(AbstractHashedMap.HashEntry<K,V> entry, V newValue)
      Updates an existing key-value mapping.

      This implementation moves the updated entry to the end of the list using moveToMRU(AbstractLinkedMap.LinkEntry).

      Overrides:
      updateEntry in class AbstractHashedMap<K,V>
      Parameters:
      entry - the entry to update
      newValue - the new value to store