Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2009 The Guava Authors
   *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
   * in compliance with the License. You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software distributed under the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
 
 package com.google.common.collect;
 
 import static com.google.common.base.Objects.firstNonNull;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.MapMakerInternalMap.Strength.SOFT;
 
 
 import java.util.Map;
 import java.util.Set;
 

A builder of java.util.concurrent.ConcurrentMap instances having any combination of the following features:

  • keys or values automatically wrapped in weak or java.lang.ref.SoftReference references
  • notification of evicted (or otherwise removed) entries
  • on-demand computation of values for keys not already present

Usage example:

   ConcurrentMap<Request, Stopwatch> timers = new MapMaker()
       .concurrencyLevel(4)
       .weakKeys()
       .makeMap();

These features are all optional; new MapMaker().makeMap() returns a valid concurrent map that behaves similarly to a java.util.concurrent.ConcurrentHashMap.

The returned map is implemented as a hash table with similar performance characteristics to java.util.concurrent.ConcurrentHashMap. It supports all optional operations of the ConcurrentMap interface. It does not permit null keys or values.

Note: by default, the returned map uses equality comparisons (the equals method) to determine equality for keys or values. However, if weakKeys() was specified, the map uses identity (==) comparisons instead for keys. Likewise, if weakValues() or softValues() was specified, the map uses identity comparisons for values.

The view collections of the returned map have weakly consistent iterators. This means that they are safe for concurrent use, but if other threads modify the map after the iterator is created, it is undefined which of these changes, if any, are reflected in that iterator. These iterators never throw java.util.ConcurrentModificationException.

If weakKeys(), weakValues(), or softValues() are requested, it is possible for a key or value present in the map to be reclaimed by the garbage collector. Entries with reclaimed keys or values may be removed from the map on each map modification or on occasional map accesses; such entries may be counted by java.util.Map.size(), but will never be visible to read or write operations. A partially-reclaimed entry is never exposed to the user. Any java.util.Map.Entry instance retrieved from the map's entry set is a snapshot of that entry's state at the time of retrieval; such entries do, however, support java.util.Map.Entry.setValue(java.lang.Object), which simply calls java.util.Map.put(java.lang.Object,java.lang.Object) on the entry's key.

The maps produced by MapMaker are serializable, and the deserialized maps retain all the configuration properties of the original map. During deserialization, if the original map had used soft or weak references, the entries are reconstructed as they were, but it's not unlikely they'll be quickly garbage-collected before they are ever accessed.

new MapMaker().weakKeys().makeMap() is a recommended replacement for java.util.WeakHashMap, but note that it compares keys using object identity whereas WeakHashMap uses java.lang.Object.equals(java.lang.Object).

Author(s):
Bob Lee
Charles Fry
Kevin Bourrillion
Since:
2.0 (imported from Google Collections Library)
@GwtCompatible(emulated = true)
public final class MapMaker extends GenericMapMaker<ObjectObject> {
  private static final int DEFAULT_INITIAL_CAPACITY = 16;
  private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
  private static final int DEFAULT_EXPIRATION_NANOS = 0;
  static final int UNSET_INT = -1;
  // TODO(kevinb): dispense with this after benchmarking
  boolean useCustomMap;
  Ticker ticker;

  
Constructs a new MapMaker instance with default settings, including strong keys, strong values, and no automatic eviction of any kind.
  public MapMaker() {}

  
Sets a custom Equivalence strategy for comparing keys.

By default, the map uses com.google.common.base.Equivalence.identity() to determine key equality when weakKeys() is specified, and com.google.common.base.Equivalence.equals() otherwise. The only place this is used is in Interners.WeakInterner.

  @GwtIncompatible("To be supported")
    checkState( == null"key equivalence was already set to %s");
     = checkNotNull(equivalence);
    this. = true;
    return this;
  }
  }

  
Sets the minimum total size for the internal hash tables. For example, if the initial capacity is 60, and the concurrency level is 8, then eight segments are created, each having a hash table of size eight. Providing a large enough estimate at construction time avoids the need for expensive resizing operations later, but setting this value unnecessarily high wastes memory.

Throws:
java.lang.IllegalArgumentException if initialCapacity is negative
java.lang.IllegalStateException if an initial capacity was already set
  public MapMaker initialCapacity(int initialCapacity) {
    checkState(this. == "initial capacity was already set to %s",
        this.);
    checkArgument(initialCapacity >= 0);
    this. = initialCapacity;
    return this;
  }
  int getInitialCapacity() {
  }

  
Specifies the maximum number of entries the map may contain. Note that the map may evict an entry before this limit is exceeded. As the map size grows close to the maximum, the map evicts entries that are less likely to be used again. For example, the map may evict an entry because it hasn't been used recently or very often.

When size is zero, elements can be successfully added to the map, but are evicted immediately. This has the same effect as invoking expireAfterWrite(0, unit) or expireAfterAccess(0, unit). It can be useful in testing, or to disable caching temporarily without a code change.

Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder.

Deprecated:
Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder, with maximumSize being replaced by com.google.common.cache.CacheBuilder.maximumSize(long). Note that CacheBuilder is simply an enhanced API for an implementation which was branched from MapMaker.
Parameters:
size the maximum size of the map
Throws:
java.lang.IllegalArgumentException if size is negative
java.lang.IllegalStateException if a maximum size was already set
  MapMaker maximumSize(int size) {
    checkState(this. == "maximum size was already set to %s",
        this.);
    checkArgument(size >= 0, "maximum size must not be negative");
    this. = size;
    this. = true;
    if ( == 0) {
      // SIZE trumps EXPIRED
      this. = .;
    }
    return this;
  }

  
Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The table is internally partitioned to try to permit the indicated number of concurrent updates without contention. Because assignment of entries to these partitions is not necessarily uniform, the actual concurrency observed may vary. Ideally, you should choose a value to accommodate as many threads as will ever concurrently modify the table. Using a significantly higher value than you need can waste space and time, and a significantly lower value can lead to thread contention. But overestimates and underestimates within an order of magnitude do not usually have much noticeable impact. A value of one permits only one thread to modify the map at a time, but since read operations can proceed concurrently, this still yields higher concurrency than full synchronization. Defaults to 4.

Note: Prior to Guava release 9.0, the default was 16. It is possible the default will change again in the future. If you care about this value, you should always choose it explicitly.

Throws:
java.lang.IllegalArgumentException if concurrencyLevel is nonpositive
java.lang.IllegalStateException if a concurrency level was already set
  public MapMaker concurrencyLevel(int concurrencyLevel) {
    checkState(this. == "concurrency level was already set to %s",
        this.);
    checkArgument(concurrencyLevel > 0);
    this. = concurrencyLevel;
    return this;
  }
  }

  
Specifies that each key (not value) stored in the map should be wrapped in a java.lang.ref.WeakReference (by default, strong references are used).

Warning: when this method is used, the resulting map will use identity (==) comparison to determine equality of keys, which is a technical violation of the java.util.Map specification, and may not be what you expect.

Throws:
java.lang.IllegalStateException if the key strength was already set
See also:
java.lang.ref.WeakReference
  @GwtIncompatible("java.lang.ref.WeakReference")
  public MapMaker weakKeys() {
    return setKeyStrength(.);
  }
    checkState( == null"Key strength was already set to %s");
     = checkNotNull(strength);
    checkArgument( != "Soft keys are not supported");
    if (strength != .) {
      // STRONG could be used during deserialization.
       = true;
    }
    return this;
  }
  }

  
Specifies that each value (not key) stored in the map should be wrapped in a java.lang.ref.WeakReference (by default, strong references are used).

Weak values will be garbage collected once they are weakly reachable. This makes them a poor candidate for caching; consider softValues() instead.

Warning: when this method is used, the resulting map will use identity (==) comparison to determine equality of values. This technically violates the specifications of the methods containsValue, remove(Object, Object) and replace(K, V, V), and may not be what you expect.

Throws:
java.lang.IllegalStateException if the value strength was already set
See also:
java.lang.ref.WeakReference
  @GwtIncompatible("java.lang.ref.WeakReference")
  public MapMaker weakValues() {
  }

  
Specifies that each value (not key) stored in the map should be wrapped in a java.lang.ref.SoftReference (by default, strong references are used). Softly-referenced objects will be garbage-collected in a globally least-recently-used manner, in response to memory demand.

Warning: in most circumstances it is better to set a per-cache maximumSize instead of using soft references. You should only use this method if you are well familiar with the practical consequences of soft references.

Warning: when this method is used, the resulting map will use identity (==) comparison to determine equality of values. This technically violates the specifications of the methods containsValue, remove(Object, Object) and replace(K, V, V), and may not be what you expect.

Deprecated:
Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder, with softValues() being replaced by com.google.common.cache.CacheBuilder.softValues(). Note that CacheBuilder is simply an enhanced API for an implementation which was branched from MapMaker. This method is scheduled for deletion in September 2014.
Throws:
java.lang.IllegalStateException if the value strength was already set
See also:
java.lang.ref.SoftReference
  @GwtIncompatible("java.lang.ref.SoftReference")
  public MapMaker softValues() {
  }
    checkState( == null"Value strength was already set to %s");
     = checkNotNull(strength);
    if (strength != .) {
      // STRONG could be used during deserialization.
       = true;
    }
    return this;
  }
  }

  
Specifies that each entry should be automatically removed from the map once a fixed duration has elapsed after the entry's creation, or the most recent replacement of its value.

When duration is zero, elements can be successfully added to the map, but are evicted immediately. This has a very similar effect to invoking maximumSize(0). It can be useful in testing, or to disable caching temporarily without a code change.

Expired entries may be counted by java.util.Map.size(), but will never be visible to read or write operations. Expired entries are currently cleaned up during write operations, or during occasional read operations in the absense of writes; though this behavior may change in the future.

Deprecated:
Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder, with expireAfterWrite(long,java.util.concurrent.TimeUnit) being replaced by com.google.common.cache.CacheBuilder.expireAfterWrite(long,java.util.concurrent.TimeUnit). Note that CacheBuilder is simply an enhanced API for an implementation which was branched from MapMaker.
Parameters:
duration the length of time after an entry is created that it should be automatically removed
unit the unit that duration is expressed in
Throws:
java.lang.IllegalArgumentException if duration is negative
java.lang.IllegalStateException if the time to live or time to idle was already set
  MapMaker expireAfterWrite(long durationTimeUnit unit) {
    checkExpiration(durationunit);
    this. = unit.toNanos(duration);
    if (duration == 0 && this. == null) {
      // SIZE trumps EXPIRED
    }
     = true;
    return this;
  }
  private void checkExpiration(long durationTimeUnit unit) {
    checkState( == "expireAfterWrite was already set to %s ns",
        );
    checkState( == "expireAfterAccess was already set to %s ns",
        );
    checkArgument(duration >= 0, "duration cannot be negative: %s %s"durationunit);
  }
  }

  
Specifies that each entry should be automatically removed from the map once a fixed duration has elapsed after the entry's last read or write access.

When duration is zero, elements can be successfully added to the map, but are evicted immediately. This has a very similar effect to invoking maximumSize(0). It can be useful in testing, or to disable caching temporarily without a code change.

Expired entries may be counted by java.util.Map.size(), but will never be visible to read or write operations. Expired entries are currently cleaned up during write operations, or during occasional read operations in the absense of writes; though this behavior may change in the future.

Deprecated:
Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder, with expireAfterAccess(long,java.util.concurrent.TimeUnit) being replaced by com.google.common.cache.CacheBuilder.expireAfterAccess(long,java.util.concurrent.TimeUnit). Note that CacheBuilder is simply an enhanced API for an implementation which was branched from MapMaker.
Parameters:
duration the length of time after an entry is last accessed that it should be automatically removed
unit the unit that duration is expressed in
Throws:
java.lang.IllegalArgumentException if duration is negative
java.lang.IllegalStateException if the time to idle or time to live was already set
  @GwtIncompatible("To be supported")
  MapMaker expireAfterAccess(long durationTimeUnit unit) {
    checkExpiration(durationunit);
    this. = unit.toNanos(duration);
    if (duration == 0 && this. == null) {
      // SIZE trumps EXPIRED
    }
     = true;
    return this;
  }
    return ( == )
  }
    return firstNonNull(, Ticker.systemTicker());
  }

  
Specifies a listener instance, which all maps built using this MapMaker will notify each time an entry is removed from the map by any means.

Each map built by this map maker after this method is called invokes the supplied listener after removing an element for any reason (see removal causes in MapMaker.RemovalCause). It will invoke the listener during invocations of any of that map's public methods (even read-only methods).

Important note: Instead of returning this as a MapMaker instance, this method returns GenericMapMaker<K, V>. From this point on, either the original reference or the returned reference may be used to complete configuration and build the map, but only the "generic" one is type-safe. That is, it will properly prevent you from building maps whose key or value types are incompatible with the types accepted by the listener already provided; the MapMaker type cannot do this. For best results, simply use the standard method-chaining idiom, as illustrated in the documentation at top, configuring a MapMaker and building your java.util.Map all in a single statement.

Warning: if you ignore the above advice, and use this MapMaker to build a map or cache whose key or value type is incompatible with the listener, you will likely experience a java.lang.ClassCastException at some undefined point in the future.

Deprecated:
Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder, with GenericMapMaker.removalListener being replaced by com.google.common.cache.CacheBuilder.removalListener(com.google.common.cache.RemovalListener). Note that CacheBuilder is simply an enhanced API for an implementation which was branched from MapMaker.
Throws:
java.lang.IllegalStateException if a removal listener was already set
  @GwtIncompatible("To be supported")
  <K, V> GenericMapMaker<K, V> removalListener(RemovalListener<K, V> listener) {
    checkState(this. == null);
    // safely limiting the kinds of maps this can produce
    @SuppressWarnings("unchecked")
    GenericMapMaker<K, V> me = (GenericMapMaker<K, V>) this;
    me.removalListener = checkNotNull(listener);
     = true;
    return me;
  }

  
Builds a thread-safe map, without on-demand computation of values. This method does not alter the state of this MapMaker instance, so it can be invoked again to create multiple independent maps.

The bulk operations putAll, equals, and clear are not guaranteed to be performed atomically on the returned map. Additionally, size and containsValue are implemented as bulk read operations, and thus may fail to observe concurrent writes.

Returns:
a serializable concurrent map having the requested features
  public <K, V> ConcurrentMap<K, V> makeMap() {
    if (!) {
      return new ConcurrentHashMap<K, V>(getInitialCapacity(), 0.75f, getConcurrencyLevel());
    }
    return ( == null)
        ? new MapMakerInternalMap<K, V>(this)
        : new NullConcurrentMap<K, V>(this);
  }

  
Returns a MapMakerInternalMap for the benefit of internal callers that use features of that class not exposed through ConcurrentMap.
  @GwtIncompatible("MapMakerInternalMap")
  <K, V> MapMakerInternalMap<K, V> makeCustomMap() {
    return new MapMakerInternalMap<K, V>(this);
  }

  
Builds a map that supports atomic, on-demand computation of values. java.util.Map.get(java.lang.Object) either returns an already-computed value for the given key, atomically computes it using the supplied function, or, if another thread is currently computing the value for this key, simply waits for that thread to finish and returns its computed value. Note that the function may be executed concurrently by multiple threads, but only for distinct keys.

New code should use com.google.common.cache.CacheBuilder, which supports statistics collection, introduces the com.google.common.cache.CacheLoader interface for loading entries into the cache (allowing checked exceptions to be thrown in the process), and more cleanly separates computation from the cache's Map view.

If an entry's value has not finished computing yet, query methods besides get return immediately as if an entry doesn't exist. In other words, an entry isn't externally visible until the value's computation completes.

java.util.Map.get(java.lang.Object) on the returned map will never return null. It may throw:

Note: Callers of get must ensure that the key argument is of type K. The get method accepts Object, so the key type is not checked at compile time. Passing an object of a type other than K can result in that object being unsafely passed to the computing function as type K, and unsafely stored in the map.

If java.util.Map.put(java.lang.Object,java.lang.Object) is called before a computation completes, other threads waiting on the computation will wake up and return the stored value.

This method does not alter the state of this MapMaker instance, so it can be invoked again to create multiple independent maps.

Insertion, removal, update, and access operations on the returned map safely execute concurrently by multiple threads. Iterators on the returned map are weakly consistent, returning elements reflecting the state of the map at some point at or since the creation of the iterator. They do not throw java.util.ConcurrentModificationException, and may proceed concurrently with other operations.

The bulk operations putAll, equals, and clear are not guaranteed to be performed atomically on the returned map. Additionally, size and containsValue are implemented as bulk read operations, and thus may fail to observe concurrent writes.

Deprecated:
Caching functionality in MapMaker has been moved to com.google.common.cache.CacheBuilder, with makeComputingMap(com.google.common.base.Function) being replaced by com.google.common.cache.CacheBuilder.build(). See the MapMaker Migration Guide for more details.
Parameters:
computingFunction the function used to compute new values
Returns:
a serializable concurrent map having the requested features
  <K, V> ConcurrentMap<K, V> makeComputingMap(
      Function<? super K, ? extends V> computingFunction) {
    return ( == null)
        ? new MapMaker.ComputingMapAdapter<K, V>(thiscomputingFunction)
        : new NullComputingConcurrentMap<K, V>(thiscomputingFunction);
  }

  
Returns a string representation for this MapMaker instance. The exact form of the returned string is not specificed.
  public String toString() {
    Objects.ToStringHelper s = Objects.toStringHelper(this);
    if ( != ) {
      s.add("initialCapacity");
    }
    if ( != ) {
      s.add("concurrencyLevel");
    }
    if ( != ) {
      s.add("maximumSize");
    }
    if ( != ) {
      s.add("expireAfterWrite" + "ns");
    }
    if ( != ) {
      s.add("expireAfterAccess" + "ns");
    }
    if ( != null) {
      s.add("keyStrength", Ascii.toLowerCase(.toString()));
    }
    if ( != null) {
      s.add("valueStrength", Ascii.toLowerCase(.toString()));
    }
    if ( != null) {
      s.addValue("keyEquivalence");
    }
    if ( != null) {
      s.addValue("removalListener");
    }
    return s.toString();
  }

  
An object that can receive a notification when an entry is removed from a map. The removal resulting in notification could have occured to an entry being manually removed or replaced, or due to eviction resulting from timed expiration, exceeding a maximum size, or garbage collection.

An instance may be called concurrently by multiple threads to process different entries. Implementations of this interface should avoid performing blocking calls or synchronizing on shared resources.

Parameters:
<K> the most general type of keys this listener can listen for; for example Object if any key is acceptable
<V> the most general type of values this listener can listen for; for example Object if any key is acceptable
  interface RemovalListener<K, V> {
    
Notifies the listener that a removal occurred at some point in the past.
    void onRemoval(RemovalNotification<K, V> notification);
  }

  
A notification of the removal of a single entry. The key or value may be null if it was already garbage collected.

Like other Map.Entry instances associated with MapMaker, this class holds strong references to the key and value, regardless of the type of references the map may be using.

  static final class RemovalNotification<K, V> extends ImmutableEntry<K, V> {
    private static final long serialVersionUID = 0;
    private final RemovalCause cause;
    RemovalNotification(@Nullable K key, @Nullable V valueRemovalCause cause) {
      super(keyvalue);
      this. = cause;
    }

    
Returns the cause for which the entry was removed.
    public RemovalCause getCause() {
      return ;
    }

    
Returns true if there was an automatic removal due to eviction (the cause is neither MapMaker.RemovalCause.EXPLICIT nor MapMaker.RemovalCause.REPLACED).
    public boolean wasEvicted() {
      return .wasEvicted();
    }
  }

  
The reason why an entry was removed.
  enum RemovalCause {
    
The entry was manually removed by the user. This can result from the user invoking java.util.Map.remove(java.lang.Object), java.util.Map.remove(java.lang.Object), or java.util.Iterator.remove().
    EXPLICIT {
      @Override
      boolean wasEvicted() {
        return false;
      }
    },

    
    REPLACED {
      @Override
      boolean wasEvicted() {
        return false;
      }
    },

    
The entry was removed automatically because its key or value was garbage-collected. This can occur when using MapMaker.softValues(), MapMaker.weakKeys(), or MapMaker.weakValues().
    COLLECTED {
      @Override
      boolean wasEvicted() {
        return true;
      }
    },

    
    EXPIRED {
      @Override
      boolean wasEvicted() {
        return true;
      }
    },

    
The entry was evicted due to size constraints. This can occur when using MapMaker.maximumSize.
    SIZE {
      @Override
      boolean wasEvicted() {
        return true;
      }
    };

    
Returns true if there was an automatic removal due to eviction (the cause is neither EXPLICIT nor REPLACED).
    abstract boolean wasEvicted();
  }

  
A map that is always empty and evicts on insertion.
  static class NullConcurrentMap<K, V> extends AbstractMap<K, V>
      implements ConcurrentMap<K, V>, Serializable {
    private static final long serialVersionUID = 0;
    private final RemovalListener<K, V> removalListener;
    private final RemovalCause removalCause;
    NullConcurrentMap(MapMaker mapMaker) {
       = mapMaker.getRemovalListener();
       = mapMaker.nullRemovalCause;
    }
    // implements ConcurrentMap
    @Override
    public boolean containsKey(@Nullable Object key) {
      return false;
    }
    @Override
    public boolean containsValue(@Nullable Object value) {
      return false;
    }
    @Override
    public V get(@Nullable Object key) {
      return null;
    }
    void notifyRemoval(K key, V value) {
      RemovalNotification<K, V> notification =
          new RemovalNotification<K, V>(keyvalue);
      .onRemoval(notification);
    }
    @Override
    public V put(K key, V value) {
      checkNotNull(key);
      checkNotNull(value);
      notifyRemoval(keyvalue);
      return null;
    }
    @Override
    public V putIfAbsent(K key, V value) {
      return put(keyvalue);
    }
    @Override
    public V remove(@Nullable Object key) {
      return null;
    }
    @Override
    public boolean remove(@Nullable Object key, @Nullable Object value) {
      return false;
    }
    @Override
    public V replace(K key, V value) {
      checkNotNull(key);
      checkNotNull(value);
      return null;
    }
    @Override
    public boolean replace(K key, @Nullable V oldValue, V newValue) {
      checkNotNull(key);
      checkNotNull(newValue);
      return false;
    }
    @Override
    public Set<Entry<K, V>> entrySet() {
      return Collections.emptySet();
    }
  }

  
Computes on retrieval and evicts the result.
  static final class NullComputingConcurrentMap<K, V> extends NullConcurrentMap<K, V> {
    private static final long serialVersionUID = 0;
    final Function<? super K, ? extends V> computingFunction;
        MapMaker mapMakerFunction<? super K, ? extends V> computingFunction) {
      super(mapMaker);
      this. = checkNotNull(computingFunction);
    }
    @SuppressWarnings("unchecked"// unsafe, which is why Cache is preferred
    @Override
    public V get(Object k) {
      K key = (K) k;
      V value = compute(key);
      checkNotNull(value + " returned null for key " + key + ".");
      notifyRemoval(keyvalue);
      return value;
    }
    private V compute(K key) {
      checkNotNull(key);
      try {
        return .apply(key);
      } catch (ComputationException e) {
        throw e;
      } catch (Throwable t) {
        throw new ComputationException(t);
      }
    }
  }

  
Overrides get() to compute on demand. Also throws an exception when null is returned from a computation.
  /*
   * This might make more sense in ComputingConcurrentHashMap, but it causes a javac crash in some
   * cases there: http://code.google.com/p/guava-libraries/issues/detail?id=950
   */
  static final class ComputingMapAdapter<K, V>
      extends ComputingConcurrentHashMap<K, V> implements Serializable {
    private static final long serialVersionUID = 0;
    ComputingMapAdapter(MapMaker mapMaker,
        Function<? super K, ? extends V> computingFunction) {
      super(mapMakercomputingFunction);
    }
    @SuppressWarnings("unchecked"// unsafe, which is one advantage of Cache over Map
    @Override
    public V get(Object key) {
      V value;
      try {
        value = getOrCompute((K) key);
      } catch (ExecutionException e) {
        Throwable cause = e.getCause();
        Throwables.propagateIfInstanceOf(causeComputationException.class);
        throw new ComputationException(cause);
      }
      if (value == null) {
        throw new NullPointerException( + " returned null for key " + key + ".");
      }
      return value;
    }
  }
New to GrepCode? Check out our FAQ X