情景

公司里一位程序员,写了段代码:

    @Override
    public Set<Integer> getUserId() {
        Set<Integer> userIdSet;
        Object value = LocalCache.getValue(CacheConstants.USERID_KEY);
        if (value != null) {
            userIdSet = (Set<Integer>) value;
        } else {
            userIdSet = redisTemplate.opsForSet().members(CacheConstants.USERID_KEY);
            LocalCache.putValue(CacheConstants.USERID_KEY, userIdSet, 300);
        }
        return userIdSet;
    }

然后判断
Set<Integer> userIdSet = taskService.getUserId();
if (task != null && userIdSet.contains(task.getUserId())) {
    //do somehting
} else {
    Loggers.RUNNING_LOG.info("unmatch, {}, {}", userIdSet.toString(),
    task.getUserId());
}   

发现它输出了的日志:

unmatch, [2, 38, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 84, 85, 86, 87, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 1000], 60

看这样子的数据, Set 里的集合,是有 60 这个值的。那为什么它是 unmatch 呢?这就很奇怪。

原因

redisTemplate.opsForSet().members()

该方法返回的是泛型数据,它的接口声明为:
Set<V> members(K key);

而且由于 redisTemplate 并没有添加泛型信息(项目中的 redis 操作,全是 string 来进行编码和解码的):

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

所以,导致

userIdSet = redisTemplate.opsForSet().members(CacheConstants.USERID_KEY);

这里的赋值,直接通过了编译(因为目前Java对泛型的支持,仅仅是通过编译器级别来实现的,而在运行时 runtime 中并没有真正支持。

所以,在实际上, userIdSet 里的是 String 类型,而不是 Integer 类型。

这样子的结果就是使用 StringSet 去调用 contains(Integer) ,肯定就会导致 false 啦,然后就出现了上面的日志的打印。

解决

知道原因,那就可以进行相应的完善啦

RedisTemplate 注入里,要加上泛型信息,即修改为

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate<String, String> redisTemplate;

然后就可以看到相关的地方会报相应的编译时错误了,然后就可以按错误信息的提示来进行修改了。

教训: 在一个有泛型的类或方法中,一定要添加泛型的信息!!以免出Bug或掉进坑。