1

我正在尝试使用 Guava 来模拟 LRU 地图。

Map<K, V> map = CacheBuilder.newBuilder()
        .maximumSize(maxSize)
        .build() // not using a cache loader
        .asMap();

但是当我尝试这样做时,我得到了一个错误。

Type mismatch: cannot convert from ConcurrentMap<Object,Object> to Map<K,V>

但是,如果我使用对缓存的临时引用创建地图,它就可以正常工作。

Cache<K, V> cache = CacheBuilder.newBuilder()
        .maximumSize(maxSize)
        .build();
Map<K, V> map = cache.asMap();

为什么这行得通而第一个样本却行不通?

4

2 回答 2

10

这是 Java 的泛型错误 - 在这种情况下无法推断出泛型类型。您应该添加<K, V>以告诉 Java 将新创建的缓存视为Cache<K, V>,而不是Cache<Object, Object>

private static <K, V> Map<K, V> makeMap(final int maxSize) {
  return CacheBuilder.newBuilder()
      .maximumSize(maxSize)
      .<K, V>build() // not using a cache loader
      .asMap();
}

然后它会工作:

final Map<Long, String> map = makeMap(10);

请参阅Angelika Langer 的Java 泛型常见问题解答的这一部分

于 2013-02-06T13:32:01.337 回答
1

这是我从 Xaerxess 的答案中得出的用法:

private final Map<String, List<Condition>> waitersByKey=MapUtil.create(5, 1000);

MapUtil.java:

import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;

public class MapUtil {

  /**
   * Value for items which are unrestricted (-1)
   */
  public static final int UNRESTRICTED=-1;

  /**
   * Create a generic map that will not exceed max size
   * @param maxSize
   * @return created map
   */
  public static <K,V> Map<K,V> createWithMaxSize(int maxSize) {
    return create(UNRESTRICTED,maxSize);
  }

  /**
   * Create a generic map that will expire objects if not accessed within a given number of minutes
   * @param expireInMins
   * @return created map
   */
  public static <K,V> Map<K,V> createWithExpiration(int expireInMins) {
    return create(expireInMins,UNRESTRICTED,UNRESTRICTED);
  }

  /**
   * Creates a map with an initial size.  Reduces growth performance hit.
   * @param initialSize
   * @return created map
   */
  public static <K,V> Map<K,V> createWithInitialSize(int initialSize) {
    return create(UNRESTRICTED,UNRESTRICTED,initialSize);
  }

  /**
   * Create generic map that expires values with max size
   * @param expireInMins max age of unaccessed items in minutes, or UNRESTRICTED
   * @param maxSize max number of items before oldest is removed, or UNRESTRICTED
   * @return created map
   */
  public static <K,V> Map<K,V> create(int expireInMins, int maxSize) {
    return create(expireInMins,maxSize,UNRESTRICTED);
  }

  /**
   * Create generic map that expires values with max size
   * @param expireInMins max age of unaccessed items in minutes, or UNRESTRICTED
   * @param maxSize max number of items before oldest is removed, or UNRESTRICTED
   * @param removalListener listener called on item removal, if not null
   * @return created map
   */
  public static <K,V> Map<K,V> create(int expireInMins, int maxSize, RemovalListener<K, V> removalListener) {
    return create(expireInMins,maxSize,UNRESTRICTED, removalListener);
  }

  /**
   * Convenience method to build a Guava cache as generic map.
   * http://stackoverflow.com/a/14730359/303442
   * @param expireInMins max age of unaccessed items in minutes, or UNRESTRICTED
   * @param maxSize max number of items before oldest is removed, or UNRESTRICTED
   * @param initialCapacity initial size in elements, reduces growth performance hit. UNRESTRICTED for default
   * @return created map
   */
  public static <K,V> Map<K,V> create(int expireInMins, int maxSize, int initialCapacity) {
    return create(expireInMins,maxSize,initialCapacity,null);
  }

  /**
   * Convenience method to build a Guava cache as generic map.
   * http://stackoverflow.com/a/14730359/303442
   * @param expireInMins max age of unaccessed items in minutes, or UNRESTRICTED
   * @param maxSize max number of items before oldest is removed, or UNRESTRICTED
   * @param initialCapacity initial size in elements, reduces growth performance hit. UNRESTRICTED for default
   * @param removalListener listener called on item removal, if not null
   * @return created map
   */
  public static <K,V> Map<K,V> create(int expireInMins, int maxSize, int initialCapacity,RemovalListener<K, V> removalListener) {
    CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
    if (expireInMins>-1)
      builder.expireAfterWrite(expireInMins, TimeUnit.MINUTES);
    if (maxSize>-1)
      builder.maximumSize(1000);
    if (initialCapacity>-1)
      builder.initialCapacity(initialCapacity);
    if (removalListener!=null)
      builder.removalListener(removalListener);
    return builder.<K,V>build().asMap();
  }
}
于 2015-03-13T16:03:41.643 回答