根据键的 class 类型动态获取映射并避免 "raw use of parameterized class 'Map'"

Get map dynamically based on key's class type and avoid "raw use of parameterized class 'Map'"

我有一个缓存 class,我用了 2 HashMap 来保存缓存。
我希望能够根据 key 的 class 类型选择正确的地图,以便:

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

为此,我构建函数 getMapToUse
问题是我必须在没有任何类型限制的情况下将其 return 类型声明为 Map 。只有这样函数才能正确编译,我才能使用 returned 映射在后续代码中存储缓存 (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;
        }
    }
}

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

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

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

所以,我将如何实现它:因为涉及 一组已知的小地图 key/value 类型 ,泛型可能不是办法。相反,我会简单地使用重载方法。 原因:调用者仍然有一个一致的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 );
    }
}