首页 > 解决方案 > 根据键的类类型动态获取地图并避免“原始使用参数化类'Map'”

问题描述

我有一个缓存类,我在其中使用 2 HashMaps 来保留缓存。
我希望能够选择正确的地图给定key的类类型,以便:

  1. 如果key是 Long,则从 map 中获取值longKeyCache
  2. 如果key是字符串,则从 map 中获取值stringKeyCache
    (假设用户只会传入 Long 或 String 键)

为此,我构建了 function getMapToUse
问题是我必须在没有任何类型限制的情况下将其返回类型清除为 Map。只有这样,函数才能正确编译,并且我能够使用返回的映射将缓存存储在后续代码 ( mapToUse.put(key, value)) 中。

该代码有效,但我收到了来自 IDE 的警告 -Raw use of parameterized class 'Map'

有没有办法解决这个警告?提前致谢。

public class CacheManager {

    private final Map<Long,String> longKeyCache = new WeakHashMap<>();
    private final Map<String,Integer> stringKeyCache = new WeakHashMap<>();

    public <K, V> V getCache(K key, Function<K, V> valueLoader) {
        Map<K, V> mapToUse = getMapToUse(key);

        return Optional.ofNullable(mapToUse.get(key))
                // cache miss
                .orElseGet(() -> {
                    V value = valueLoader.apply(key);
                    mapToUse.put(key, value);
                    return value;
                });
    }

    // warning: Raw use of parameterized class 'Map'
    private <K> Map getMapToUse(K key) {
        if (key instanceof Long) {
            return longKeyCache;
        } else {
            return stringKeyCache;
        }
    }
}

标签: javagenericscaching

解决方案


如果您想保留这种设计(CacheManager“知道”两个具有不同类型的键和值的映射),那么您将不得不将映射转换为Map<K, V>. 没有逃避这一点,因为编译器将无法猜测是哪种实际类型。

您将意识到泛型的目的之一是允许实现可以使用各种类型的相同功能,但同时应用类型安全检查。

该方法getCache( K, Function<K, V> )正在返回V,这意味着它V可能是Integeror String。但是哪一个??编译器必须在方法被调用的地方归结为一个。

所以,这就是我将如何实现它:因为涉及到一组已知的小型映射键/值类型,所以泛型可能不是方法。相反,我会简单地使用重载方法。原因:调用者仍然有一个一致的 API,即编译时类型检查,这是泛型的主要目标。

public class CacheManager{
    private final Map<Long,String> longKeyCache = new WeakHashMap<>();
    private final Map<String,Integer> stringKeyCache = new WeakHashMap<>();
    
    public String getCache( Long key, Function<Long, String> valueLoader) {
        return Optional.ofNullable( longKeyCache.get(key) )
                // cache miss
                .orElseGet(() -> {
                    String value = valueLoader.apply(key);
                    longKeyCache.put(key, value);
                    return value;
                });
    }
    
    public Integer getCache( String key, Function<String, Integer> valueLoader) {
        return Optional.ofNullable( stringKeyCache.get(key) )
                // cache miss
                .orElseGet(() -> {
                    Integer value = valueLoader.apply(key);
                    stringKeyCache.put(key, value);
                    return value;
                });
    }
    
    /* Testing code from here on. */
    public static void main( String[] args ){
        CacheManager cm = new CacheManager();
        cm.addTestData();
        
        System.out.println( cm.getCache( 200L, k -> k.toString() ) );
        System.out.println( cm.getCache( "500S", k -> 800 ) );
        System.out.println( cm.getCache( "900", k -> 900 ) );
    }
    
    private void addTestData() {
        longKeyCache.put( 200L, "200S" );
        longKeyCache.put( 201L, "201S" );
        stringKeyCache.put( "500S", 500 );
        stringKeyCache.put( "501S", 501 );
    }
}

推荐阅读