【问题标题】:Get map dynamically based on key's class type and avoid "raw use of parameterized class 'Map'"根据键的类类型动态获取地图,避免“原始使用参数化类'Map'”
【发布时间】:2021-12-06 01:08:12
【问题描述】:

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

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

为此,我构建了函数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;
        }
    }
}

【问题讨论】:

    标签: java generics caching


    【解决方案1】:

    如果您想保留这种设计(拥有一个“知道”两个具有不同类型的键和值的映射的CacheManager),那么您将不得不在某个地方或另一个地方将地图投射到Map&lt;K, V&gt;。没有逃避这一点,因为编译器将无法猜测是指哪个实际类型。

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

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

    所以,这就是我的实现方式:因为涉及一组已知的小型映射键/值类型,所以泛型可能不是方法。相反,我会简单地使用重载方法。 原因:调用者仍然有一个一致的 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 );
        }
    }
    

    【讨论】:

    • 谢谢@Sree。我们最终采用了类似的解决方案——为每个映射创建一个getXXX 函数来进行类型检查。在getXXX函数内部,我们仍然调用了泛型函数,但是有一个额外的参数来传递对应的map给它,这样我们仍然得到了一定程度的抽象
    猜你喜欢
    • 2016-06-27
    • 2019-01-08
    • 2023-01-20
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多