【问题标题】:why HashSet constructed from redis zset keeps sorted?为什么从 redis zset 构造的 HashSet 保持排序?
【发布时间】:2019-08-30 15:35:24
【问题描述】:

在 Java 中,HashSet 是未排序的,如下所示:

        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(4);
        set.add(3);
        set.add(2);
        set.add(5);
        set.forEach(e-> System.out.print(e+" "));

它的输出是:

1 2 3 4 5

当java set来自zset时,像这样:

redisTemplate.opsForZSet().add(key, 1, 0);
redisTemplate.opsForZSet().add(key, 4, 1);
redisTemplate.opsForZSet().add(key, 3, 2);
redisTemplate.opsForZSet().add(key, 2, 3);
redisTemplate.opsForZSet().add(key, 5, 4);
Set<Integer> set = redisTemplate.opsForZSet().range(key, 0, -1);
System.out.println(set.getClass());
set.forEach(e-> System.out.print(e+" "));

输出是:

java.util.HashSet
1 4 3 2 5

为什么此时输出保持顺序作为输入?

【问题讨论】:

    标签: redis jedis spring-cache


    【解决方案1】:

    ZSET 是按分数排序的,而不是 ZSET 中成员的键。所以在你的例子中:

    redisTemplate.opsForZSet().add(key, 1, 0);
    redisTemplate.opsForZSet().add(key, 4, 1);
    redisTemplate.opsForZSet().add(key, 3, 2);
    redisTemplate.opsForZSet().add(key, 2, 3);
    redisTemplate.opsForZSet().add(key, 5, 4);
    

    1 的得分为 05 的得分为 4。如果您将其更改为:

    redisTemplate.opsForZSet().add(key, 1, 1);
    redisTemplate.opsForZSet().add(key, 4, 4);
    redisTemplate.opsForZSet().add(key, 3, 3);
    redisTemplate.opsForZSet().add(key, 2, 2);
    redisTemplate.opsForZSet().add(key, 5, 5);
    

    你应该得到预期的结果。

    【讨论】:

    • 是的,我知道 zset 的功能。但令我困惑的是java hashSet。 java set实例应该不包含分数信息,为什么还是有序的?
    • Java set 不保证条目是有序的,在这种情况下您可能会看到有序的输出,但您不能依赖它来编写业务逻辑。
    【解决方案2】:

    jedis 返回的不是纯 hashSet 而是 LinkedHashSet,其中元素是有序的。

    package org.springframework.data.redis.serializer;
    
    public abstract class SerializationUtils {
        static <T extends Collection<?>> T deserializeValues(Collection<byte[]> rawValues, Class<T> type,
                RedisSerializer<?> redisSerializer) {
            // connection in pipeline/multi mode
            if (rawValues == null) {
                return null;
            }
    
            Collection<Object> values = (List.class.isAssignableFrom(type) ? new ArrayList<Object>(rawValues.size())
                    : new LinkedHashSet<Object>(rawValues.size()));
            for (byte[] bs : rawValues) {
                values.add(redisSerializer.deserialize(bs));
            }
    
            return (T) values;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-11
      • 2010-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多