问题

//真实代码
Map<Integer, String> m = chatTagMapper.selectBatchIds(returnTagIds)
                .stream()
                .collect(Collectors.toMap(ChatTagEntity::getId, ChatTagEntity::getName));
        tagNames.addAll(m.values());
        return tagNames;
//问题
本地正常,开发环境,tagNames和查询的顺序不一样。
定位到java 版本不一样,输出不同。

测试

List<User> users = new ArrayList<>();
        User user = new User();
        user.name = "Luna";
        user.id = 36;
        users.add(user);

        user = new User();
        user.name = "Luna2";
        user.id = 100;
        users.add(user);

        user = new User();
        user.name = "Luna3";
        user.id = 101;
        users.add(user);

        Map<Integer, String> x = users
                .stream()
                .collect(Collectors.toMap(User::getId, User::getName));
        System.out.println(x);

//java8 执行 和输入熟悉不一样
{100=Luna2, 36=Luna, 101=Luna3}
//java11 执行 和输入顺序一样
{36=Luna, 100=Luna2, 101=Luna3}

原因

Java 8 的实现

public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper) {
        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);

public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID)

底层调用的是HashMap的 merge 方法。merge 方法会计算哈希值,HashMap内部容器初始大小 16。

处理过程:

Untitled

最终 print 的时候,100在 36 前面。

Java 11的实现

public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper) {
        return new CollectorImpl<>(HashMap::new,
                                   uniqKeysMapAccumulator(keyMapper, valueMapper),
                                   uniqKeysMapMerger(),
                                   CH_ID);
//底层调用的是putIfAbsent
private static <T, K, V>
    BiConsumer<Map<K, V>, T> uniqKeysMapAccumulator(Function<? super T, ? extends K> keyMapper,
                                                    Function<? super T, ? extends V> valueMapper) {
        return (map, element) -> {
            K k = keyMapper.apply(element);
            V v = Objects.requireNonNull(valueMapper.apply(element));
            V u = map.putIfAbsent(k, v);
            if (u != null) throw duplicateKeyException(k, u, v);
        };
    }

调用的是 putIfAbsent,底层调用的 putVal,是插入到了链表队尾,而不是头部