Class SmoothieMap<K,​V>

  • Type Parameters:
    K - the type of keys maintained by this map
    V - the type of mapped values
    All Implemented Interfaces:
    ObjObjMap<K,​V>, Map<K,​V>

    public class SmoothieMap<K,​V>
    extends Object
    implements ObjObjMap<K,​V>
    Unordered Map with worst put latencies more than 100 times smaller than in ordinary hash table implementations like HashMap and very low footprint per entry. SmoothieMap may also operate in the "low-garbage" or the "footprint" modes.

    SmoothieMap is created using a builder: SmoothieMap.newBuilder().build(). See possible configurations in the documentation for SmoothieMapBuilder.

    Unlike HashMap, but like ConcurrentHashMap, Map.of() immutable Maps, and Guava's ImmutableMaps, SmoothieMap does not support null key and values. An attempt to put null key or value, or query null key or value (e. g. via get(null)), leads to a NullPointerException.

    SmoothieMap supports pluggable keys' and values' equivalences which could be configured in the builder, via SmoothieMapBuilder.keyEquivalence(Equivalence) and SmoothieMapBuilder.valueEquivalence(Equivalence) methods.

    Functional additions to the Map interface implemented by SmoothieMap are described in the documentation for ObjObjMap interface. It also provides sizeInBytes() to track the footprint of the map.

    Note that this implementation is not synchronized. If multiple threads access a SmoothieMap concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map.

    If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

       Map m = Collections.synchronizedMap(smoothieMap);

    In terms of performance, favor calling bulk methods like forEach(BiConsumer) to iterating the SmoothieMap via Iterator, including for-each style iterations on map's collections views. Especially if you need to remove entries during iteration (i. e. call Iterator.remove()) and hash code for key objects is not cached on their side (like it is cached, for example, in String class) - try to express your logic using removeIf(BiPredicate) method in this case.

    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      Map<K,​V> asMapWithMutableIterators()  
      void clear()
      Removes all of the mappings from this map.
      @Nullable V compute​(K key, BiFunction<? super K,​? super @Nullable V,​? extends @Nullable V> remappingFunction)
      Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping).
      @Nullable V computeIfAbsent​(K key, Function<? super K,​? extends @Nullable V> mappingFunction)
      If the specified key is not already associated with a value, attempts to compute its value using the given mapping function and enters it into this map unless null.
      @Nullable V computeIfPresent​(K key, BiFunction<? super K,​? super V,​? extends @Nullable V> remappingFunction)
      If the value for the specified key is present and non-null, attempts to compute a new mapping given the key and its current mapped value.
      boolean containsEntry​(Object key, Object value)
      Returns true if this map contains a mapping of the given key and value.
      boolean containsKey​(Object key)
      Returns true if this map contains a mapping for the specified key.
      boolean containsValue​(Object value)
      Returns true if this map has one or more keys associated with the specified value.
      ObjSet<Map.Entry<K,​V>> entrySet()
      Returns a Set view of the mappings contained in this map.
      boolean equals​(Object obj)
      Returns true if the other object is a Map; this map and the given map have the same size; and for all entries in the other map, containsEntry(e.getKey(), e.getValue()) called on this map returns true.
      void forEach​(BiConsumer<? super K,​? super V> action)
      Performs the given action for each entry in this map until all entries have been processed or the action throws an exception.
      boolean forEachWhile​(BiPredicate<? super K,​? super V> predicate)
      Checks the given predicate on each entry in this map until all entries have been processed or the predicate returns false for some entry, or throws an Exception.
      @Nullable V get​(Object key)
      Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
      @Nullable K getInternalKey​(Object key)
      Returns the key object held by this map internally and equivalent to the specified key, if there is one, or null if this map contains no mapping for the key.
      V getOrDefault​(Object key, V defaultValue)
      Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.
      int hashCode()
      Returns a sum of the following expressions: keyEquivalence().hash(key) ^ valueEquivalence().hash(value) applied to all entries in this map.
      boolean isEmpty()  
      Equivalence<K> keyEquivalence()
      Returns the equivalence strategy for keys for this map.
      ObjSet<K> keySet()
      Returns a Set view of the keys contained in this map.
      @Nullable V merge​(K key, V value, BiFunction<? super V,​? super V,​? extends @Nullable V> remappingFunction)
      If the specified key is not already associated with a value or is associated with null, associates it with the given value.
      Iterator<Map.Entry<K,​V>> mutableEntryIterator()
      Returns an iterator over the entries in this SmoothieMap that supports Iterator.remove() operation.
      Iterator<K> mutableKeyIterator()
      Returns an iterator over the keys in this SmoothieMap that supports Iterator.remove() operation.
      Iterator<V> mutableValueIterator()
      Returns an iterator over the values in this SmoothieMap that supports Iterator.remove() operation.
      static <K,​V>
      SmoothieMapBuilder<K,​V>
      newBuilder()
      Creates a new SmoothieMapBuilder.
      @Nullable V put​(K key, V value)
      Associates the specified value with the specified key in this map.
      void putAll​(Map<? extends K,​? extends V> m)
      Copies all of the mappings from the specified map to this map.
      @Nullable V putIfAbsent​(K key, V value)
      If the specified key is not already associated with a value, associates it with the given value and returns null, else returns the current value.
      @Nullable V remove​(Object key)
      Removes the mapping for a key from this map if it is present.
      boolean remove​(Object key, Object value)
      Removes the entry for the specified key only if it is currently mapped to the specified value.
      boolean removeIf​(BiPredicate<? super K,​? super V> filter)
      Removes all of the entries of this map that satisfy the given predicate.
      V replace​(K key, V value)
      Replaces the entry for the specified key only if it is currently mapped to some value.
      boolean replace​(K key, V oldValue, V newValue)
      Replaces the entry for the specified key only if currently mapped to the specified value.
      void replaceAll​(BiFunction<? super K,​? super V,​? extends V> function)
      Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception.
      int size()  
      long sizeAsLong()
      Returns the number of entries in the map as a long value (not truncated to Integer.MAX_VALUE, if the map size exceeds it, as returned by the Map.size() method).
      long sizeInBytes()
      Returns the approximate footprint of this SmoothieMap instance in the heap of the JVM process, in bytes.
      String toString()  
      Equivalence<V> valueEquivalence()
      Returns the equivalence strategy for values for this map.
      Collection<V> values()
      Returns a Collection view of the values contained in this map.
    • Method Detail

      • sizeInBytes

        public final long sizeInBytes()
        Returns the approximate footprint of this SmoothieMap instance in the heap of the JVM process, in bytes. Does not include the footprints of the keys and values stored in the SmoothieMap.
        Returns:
        the approximate footprint of this SmoothieMap proper
      • size

        public final int size()
        Specified by:
        size in interface Map<K,​V>
      • sizeAsLong

        public final long sizeAsLong()
        Description copied from interface: ObjObjMap
        Returns the number of entries in the map as a long value (not truncated to Integer.MAX_VALUE, if the map size exceeds it, as returned by the Map.size() method).
        Specified by:
        sizeAsLong in interface ObjObjMap<K,​V>
        Returns:
        the number of key-value mappings in this map
        See Also:
        Map.size(), ObjObjMap.mappingCount()
      • isEmpty

        public final boolean isEmpty()
        Specified by:
        isEmpty in interface Map<K,​V>
      • containsKey

        public final boolean containsKey​(Object key)
        Description copied from interface: ObjObjMap
        Returns true if this map contains a mapping for the specified key. More formally, returns true if and only if this map contains a mapping for a key k such that the specified key and k are equivalent. (There can be at most one such mapping.)
        Specified by:
        containsKey in interface Map<K,​V>
        Specified by:
        containsKey in interface ObjObjMap<K,​V>
        Parameters:
        key - key whose presence in this map is to be tested
        Returns:
        true if this map contains a mapping for the specified key
      • containsEntry

        public final boolean containsEntry​(Object key,
                                           Object value)
        Description copied from interface: ObjObjMap
        Returns true if this map contains a mapping of the given key and value. More formally, this map should contain a mapping from a key k to a value v such that the specified key and k are equivalent with regard to ObjObjMap.keyEquivalence(), and the specified value and v are equivalent with regard to ObjObjMap.valueEquivalence(). (There can be at most one such mapping.)
        Specified by:
        containsEntry in interface ObjObjMap<K,​V>
        Parameters:
        key - the key of the mapping to check presence of
        value - the value of the mapping to check presence of
        Returns:
        true if this map contains the specified mapping, false otherwise
      • getOrDefault

        public final V getOrDefault​(Object key,
                                    V defaultValue)
        Description copied from interface: ObjObjMap
        Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.
        Specified by:
        getOrDefault in interface Map<K,​V>
        Specified by:
        getOrDefault in interface ObjObjMap<K,​V>
        Parameters:
        key - the key whose associated value is to be returned
        defaultValue - the default mapping of the key
        Returns:
        the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key
      • remove

        @CanIgnoreReturnValue
        public final @Nullable V remove​(Object key)
        Description copied from interface: ObjObjMap
        Removes the mapping for a key from this map if it is present. More formally, if this map contains a mapping from key k to value v such that the specified key and k are equivalent, that mapping is removed. (The map can contain at most one such mapping.)

        Returns the value to which this map previously associated the key, or null if the map contained no mapping for the key.

        The map will not contain a mapping for the specified key once the call returns.

        Specified by:
        remove in interface Map<K,​V>
        Specified by:
        remove in interface ObjObjMap<K,​V>
        Parameters:
        key - key whose mapping is to be removed from the map
        Returns:
        the previous value associated with key, or null if there was no mapping for key
      • remove

        public final boolean remove​(Object key,
                                    Object value)
        Description copied from interface: ObjObjMap
        Removes the entry for the specified key only if it is currently mapped to the specified value. Values are compared using ObjObjMap.valueEquivalence().
        Specified by:
        remove in interface Map<K,​V>
        Specified by:
        remove in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is associated
        value - value expected to be associated with the specified key
        Returns:
        true if the value was removed
      • replace

        public final V replace​(K key,
                               V value)
        Description copied from interface: ObjObjMap
        Replaces the entry for the specified key only if it is currently mapped to some value.
        Specified by:
        replace in interface Map<K,​V>
        Specified by:
        replace in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is associated
        value - value to be associated with the specified key
        Returns:
        the previous value associated with the specified key, or null if there was no mapping for the key.
      • replace

        public final boolean replace​(K key,
                                     V oldValue,
                                     V newValue)
        Description copied from interface: ObjObjMap
        Replaces the entry for the specified key only if currently mapped to the specified value. Values are compared using ObjObjMap.valueEquivalence().
        Specified by:
        replace in interface Map<K,​V>
        Specified by:
        replace in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is associated
        oldValue - value expected to be associated with the specified key
        newValue - value to be associated with the specified key
        Returns:
        true if the value was replaced
      • put

        @CanIgnoreReturnValue
        public final @Nullable V put​(K key,
                                     V value)
        Description copied from interface: ObjObjMap
        Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced by the specified value. (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.)
        Specified by:
        put in interface Map<K,​V>
        Specified by:
        put in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is to be associated
        value - value to be associated with the specified key
        Returns:
        the previous value associated with key, or null if there was no mapping for key
      • putIfAbsent

        public final @Nullable V putIfAbsent​(K key,
                                             V value)
        Description copied from interface: ObjObjMap
        If the specified key is not already associated with a value, associates it with the given value and returns null, else returns the current value.
        Specified by:
        putIfAbsent in interface Map<K,​V>
        Specified by:
        putIfAbsent in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is to be associated
        value - value to be associated with the specified key
        Returns:
        the previous value associated with the specified key, or null if there was no mapping for the key
      • get

        public final @Nullable V get​(Object key)
        Description copied from interface: ObjObjMap
        Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.

        More formally, if this map contains a mapping from a key k to a value v such that the specified key and k are equivalent, then this method returns v; otherwise it returns null. (There can be at most one such mapping.)

        Specified by:
        get in interface Map<K,​V>
        Specified by:
        get in interface ObjObjMap<K,​V>
        Parameters:
        key - the key whose associated value is to be returned
        Returns:
        the value to which the specified key is mapped, or null if this map contains no mapping for the key
      • getInternalKey

        public final @Nullable K getInternalKey​(Object key)
        Description copied from interface: ObjObjMap
        Returns the key object held by this map internally and equivalent to the specified key, if there is one, or null if this map contains no mapping for the key.

        This method could be used to deduplicate objects in the application, to reduce the memory footprint and make the application to conform to the "most objects die young" hypothesis that most GC algorithms are optimized for. This method is functionally similar to String.intern() and Guava's Interner, but allows to piggy-back a map data structure which may already exist in an application.

        ObjObjMap.keySet().getInternal(key) delegates to this method.

        Specified by:
        getInternalKey in interface ObjObjMap<K,​V>
        Parameters:
        key - the key whose equivalent held by this map internally is to be returned
        Returns:
        the map-internal equivalent of the specified key, or null if the map contains no mapping for the specified key
      • computeIfPresent

        public final @Nullable V computeIfPresent​(K key,
                                                  BiFunction<? super K,​? super V,​? extends @Nullable V> remappingFunction)
        Description copied from interface: ObjObjMap
        If the value for the specified key is present and non-null, attempts to compute a new mapping given the key and its current mapped value.

        If the function returns null, the mapping is removed. If the function itself throws an (unchecked) exception, the exception is rethrown, and the current mapping is left unchanged.

        Specified by:
        computeIfPresent in interface Map<K,​V>
        Specified by:
        computeIfPresent in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is to be associated
        remappingFunction - the function to compute a value
        Returns:
        the new value associated with the specified key, or null if none
      • computeIfAbsent

        public final @Nullable V computeIfAbsent​(K key,
                                                 Function<? super K,​? extends @Nullable V> mappingFunction)
        Description copied from interface: ObjObjMap
        If the specified key is not already associated with a value, attempts to compute its value using the given mapping function and enters it into this map unless null.

        If the function returns null no mapping is recorded. If the function itself throws an (unchecked) exception, the exception is rethrown, and no mapping is recorded. The most common usage is to construct a new object serving as an initial mapped value or memoized result, as in:

         
         map.computeIfAbsent(key, k -> new Value(f(k)));
         

        Or to implement a multi-value map, Map<K,Collection<V>>, supporting multiple values per key:

         
         map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
         
        Specified by:
        computeIfAbsent in interface Map<K,​V>
        Specified by:
        computeIfAbsent in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is to be associated
        mappingFunction - the function to compute a value
        Returns:
        the current (existing or computed) value associated with the specified key, or null if the computed value is null
      • compute

        public final @Nullable V compute​(K key,
                                         BiFunction<? super K,​? super @Nullable V,​? extends @Nullable V> remappingFunction)
        Description copied from interface: ObjObjMap
        Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). For example, to either create or append a String msg to a value mapping:
         
         map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))
        (Method merge() is often simpler to use for such purposes.)

        If the function returns null, the mapping is removed (or remains absent if initially absent). If the function itself throws an (unchecked) exception, the exception is rethrown, and the current mapping is left unchanged.

        Specified by:
        compute in interface Map<K,​V>
        Specified by:
        compute in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the specified value is to be associated
        remappingFunction - the function to compute a value
        Returns:
        the new value associated with the specified key, or null if none
      • merge

        public final @Nullable V merge​(K key,
                                       V value,
                                       BiFunction<? super V,​? super V,​? extends @Nullable V> remappingFunction)
        Description copied from interface: ObjObjMap
        If the specified key is not already associated with a value or is associated with null, associates it with the given value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null. This method may be of use when combining multiple mapped values for a key. For example, to either create or append a String msg to a value mapping:
         
         map.merge(key, msg, String::concat)
         

        If the function returns null the mapping is removed. If the function itself throws an (unchecked) exception, the exception is rethrown, and the current mapping is left unchanged.

        Specified by:
        merge in interface Map<K,​V>
        Specified by:
        merge in interface ObjObjMap<K,​V>
        Parameters:
        key - key with which the resulting value is to be associated
        value - the value to be merged with the existing value associated with the key or, if no existing value is associated with the key, to be associated with the key
        remappingFunction - the function to recompute a value if present
        Returns:
        the new value associated with the specified key, or null if no value is associated with the key
      • forEach

        public final void forEach​(BiConsumer<? super K,​? super V> action)
        Description copied from interface: ObjObjMap
        Performs the given action for each entry in this map until all entries have been processed or the action throws an exception. Actions are performed in the order of entry set iteration. Exceptions thrown by the action are relayed to the caller.

        The entries will be processed in the same order as they appear the entry set's iterator and ObjObjMap.forEachWhile(BiPredicate).

        Specified by:
        forEach in interface Map<K,​V>
        Specified by:
        forEach in interface ObjObjMap<K,​V>
        Parameters:
        action - The action to be performed for each entry
        See Also:
        ObjObjMap.forEachWhile(BiPredicate)
      • forEachWhile

        public final boolean forEachWhile​(BiPredicate<? super K,​? super V> predicate)
        Description copied from interface: ObjObjMap
        Checks the given predicate on each entry in this map until all entries have been processed or the predicate returns false for some entry, or throws an Exception. Exceptions thrown by the predicate are relayed to the caller.

        The entries will be processed in the same order as they appear in the entry set's iterator and ObjObjMap.forEach(BiConsumer).

        If the map is empty, this method returns true immediately.

        Specified by:
        forEachWhile in interface ObjObjMap<K,​V>
        Parameters:
        predicate - the predicate to be checked for each entry
        Returns:
        true if the map is empty, or if the predicate returned true for all entries of the map, false if the predicate returned false for some entry
        See Also:
        ObjObjMap.forEach(BiConsumer)
      • replaceAll

        public final void replaceAll​(BiFunction<? super K,​? super V,​? extends V> function)
        Description copied from interface: ObjObjMap
        Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception. Exceptions thrown by the function are relayed to the caller.
        Specified by:
        replaceAll in interface Map<K,​V>
        Specified by:
        replaceAll in interface ObjObjMap<K,​V>
        Parameters:
        function - the function to apply to each entry
      • containsValue

        public final boolean containsValue​(Object value)
        Description copied from interface: ObjObjMap
        Returns true if this map has one or more keys associated with the specified value. More formally, returns true if and only if this map contains at least one mapping to a value v such that ObjObjMap.valueEquivalence().equivalent(value, v) == true. This operation requires time linear in the map size.
        Specified by:
        containsValue in interface Map<K,​V>
        Specified by:
        containsValue in interface ObjObjMap<K,​V>
        Parameters:
        value - value whose presence in this map is to be tested
        Returns:
        true if this map maps one or more keys to the specified value
      • putAll

        public final void putAll​(Map<? extends K,​? extends V> m)
        Description copied from interface: ObjObjMap
        Copies all of the mappings from the specified map to this map. The effect of this call is equivalent to that of calling put(k, v) on this map once for each mapping from key k to value v in the specified map. The behavior of this operation is undefined if the specified map is modified while the operation is in progress.
        Specified by:
        putAll in interface Map<K,​V>
        Specified by:
        putAll in interface ObjObjMap<K,​V>
        Parameters:
        m - mappings to be stored in this map
      • clear

        public final void clear()
        Description copied from interface: ObjObjMap
        Removes all of the mappings from this map. The map will be empty after this call returns.
        Specified by:
        clear in interface Map<K,​V>
        Specified by:
        clear in interface ObjObjMap<K,​V>
      • removeIf

        public final boolean removeIf​(BiPredicate<? super K,​? super V> filter)
        Description copied from interface: ObjObjMap
        Removes all of the entries of this map that satisfy the given predicate. Errors or runtime exceptions thrown during iteration or by the predicate are relayed to the caller.

        Note the order in which this method visits entries may be different from the iteration and ObjObjMap.forEach(BiConsumer) order.

        Specified by:
        removeIf in interface ObjObjMap<K,​V>
        Parameters:
        filter - a predicate which returns true for entries to be removed
        Returns:
        true if any entries were removed
      • mutableKeyIterator

        public Iterator<K> mutableKeyIterator()
        Returns an iterator over the keys in this SmoothieMap that supports Iterator.remove() operation. This method may be usable because iterator of keySet() may not support Iterator.remove().
        Returns:
        a remove-supporting iterator over the keys in this SmoothieMap
      • mutableValueIterator

        public Iterator<V> mutableValueIterator()
        Returns an iterator over the values in this SmoothieMap that supports Iterator.remove() operation. This method may be usable because iterator of values() may not support Iterator.remove().
        Returns:
        a remove-supporting iterator over the values in this SmoothieMap
      • mutableEntryIterator

        public Iterator<Map.Entry<K,​V>> mutableEntryIterator()
        Returns an iterator over the entries in this SmoothieMap that supports Iterator.remove() operation. This method may be usable because iterator of entrySet() may not support Iterator.remove().
        Returns:
        a remove-supporting iterator over the entries in this SmoothieMap
      • asMapWithMutableIterators

        public Map<K,​V> asMapWithMutableIterators()