Java 在流上使用Collections.toMap()时,如何保持列表的迭代顺序?

Java 在流上使用Collections.toMap()时,如何保持列表的迭代顺序?,java,collections,java-8,java-stream,Java,Collections,Java 8,Java Stream,我正在从列表创建地图,如下所示: List<String> strings = Arrays.asList("a", "bb", "ccc"); Map<String, Integer> map = strings.stream() .collect(Collectors.toMap(Function.identity(), String::length)); List strings=Arrays.asList(“a”、“bb”、“ccc”); Map Ma

我正在从
列表创建
地图
,如下所示:

List<String> strings = Arrays.asList("a", "bb", "ccc");

Map<String, Integer> map = strings.stream()
    .collect(Collectors.toMap(Function.identity(), String::length));
List strings=Arrays.asList(“a”、“bb”、“ccc”);
Map Map=strings.stream()
.collect(Collectors.toMap(Function.identity(),String::length));
我想保持与
列表中相同的迭代顺序。如何使用
Collectors.toMap()
方法创建
LinkedHashMap

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);
}
与:

或者编写一个新的
toLinkedMap()
方法并使用该方法使其更干净:

public class MoreCollectors
{
    public static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedMap(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends U> valueMapper)
    {
        return Collectors.toMap(
            keyMapper,
            valueMapper, 
            (u, v) -> {
                throw new IllegalStateException(String.format("Duplicate key %s", u));
            },
            LinkedHashMap::new
        );
    }
}
公共类收集器
{
公共静态收集器toLinkedMap(

功能制造您自己的
供应商
累加器
组合器

List myList=Arrays.asList(“a”、“bb”、“ccc”);
//或自java 9列表(“a”、“bb”、“ccc”);
LinkedHashMap MapInNorder=myList
.stream()
.收集(
LinkedHashMap::新建,//供应商
(map,item)->map.put(item,item.length()),//累加器
Map::putAll);//组合器
System.out.println(mapInOrder);/{a=1,bb=2,ccc=3}
在Kotlin中,是保持秩序的


map
的基础集合是一个
LinkedHashMap
(按插入顺序)。

通过一些字段映射对象数组的简单函数:

public static <T, E> Map<E, T> toLinkedHashMap(List<T> list, Function<T, E> someFunction) {
    return list.stream()
               .collect(Collectors.toMap(
                   someFunction, 
                   myObject -> myObject, 
                   (key1, key2) -> key1, 
                   LinkedHashMap::new)
               );
}


Map<String, MyObject> myObjectsByIdMap1 = toLinkedHashMap(
                listOfMyObjects, 
                MyObject::getSomeStringField()
);

Map<Integer, MyObject> myObjectsByIdMap2 = toLinkedHashMap(
                listOfMyObjects, 
                MyObject::getSomeIntegerField()
);
公共静态映射到LinkedHashMap(列表,函数someFunction){
return list.stream()
.collect(collector.toMap)(
某些功能,
myObject->myObject,
(键1,键2)->键1,
LinkedHashMap::新建)
);
}
映射MyObjectsBydMap1=toLinkedHashMap(
对象列表,
MyObject::getSomeStringField()
);
映射MyObjectsBydMap2=toLinkedHashMap(
对象列表,
MyObject::getSomeIntegerField()
);
自Java 9以来,您可以按照与原始列表相同的顺序收集以下列表:

List strings=Arrays.asList(“a”、“bb”、“ccc”);
列表条目=strings.stream()
.map(e->map.entry(e,e.length())
.collect(Collectors.toList());
System.out.println(条目);//[a=1,bb=2,ccc=3]
或者,您也可以使用相同的方式通过单个条目收集列表:

List strings=Arrays.asList(“a”、“bb”、“ccc”);
列表映射=strings.stream()
.map(e->map.of(e,e.length())
.collect(Collectors.toList());
System.out.println(maps);//[{a=1},{bb=2},{ccc=3}]

解决此问题的正确方法是

当前---->2参数版本

Map-mapping=list.stream().collect(Collectors.toMap(Entity::getId,Entity::getName));

右----->使用Collectors.toMap的4参数版本告诉供应商提供新的LinkedHashMap:

Map-mapping=list.stream().collect(Collectors.toMap(Entity::getId,Entity::getName,(u,v)->u,LinkedHashMap::new));


这会有帮助。

为什么会如此复杂?您可以很容易地做到这一点,检查我下面的答案
mergeFunction
在4参数版本
Collectors.toMap()中的答案
不知道要合并哪个键,而
u
v
都是值。因此,关于IllegalStateException的消息不是那么正确。@hzitoun因为如果您简单地使用
Map::put
,您将(可能)得到同一个键有不同的值。通过使用
Map::put
,您间接地选择了遇到的第一个值不正确。这是最终用户想要的吗?您确定吗?如果是,那么确定,使用
Map::put
。否则,您不确定也无法决定:让用户知道他们的流映射到了两个相同的带有d的键不同的值。我会对您自己的答案发表评论,但它当前被锁定。请检查我下面的答案。对于您的
流的
收集
方法,使用自定义
供应商
累加器
组合器
,它只有4行代码。)这个问题已经得到了回答,我只想列出找到这个问题答案的路径。(1)你想要在地图中排序,你必须使用LinkedHashMap(2)Collectors.toMap()有许多实现,其中一个要求映射。所以在需要映射的地方使用LinkedHashMap。@Sushil接受的答案允许重用逻辑您知道什么更快吗?使用您的版本还是接受的答案?@Nikolas您能解释一下副作用的意思吗?我实际上有问题要决定选择哪一个:@NikolasCharalambidis,什么副作用?它是一个累加器。
java.util.stream.Collectors#uniqkeysmappacculator
做同样的事情。
public class MoreCollectors
{
    public static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedMap(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends U> valueMapper)
    {
        return Collectors.toMap(
            keyMapper,
            valueMapper, 
            (u, v) -> {
                throw new IllegalStateException(String.format("Duplicate key %s", u));
            },
            LinkedHashMap::new
        );
    }
}
fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V>
public fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V> {
    if (this is Collection) {
        return when (size) {
            0 -> emptyMap()
            1 -> mapOf(if (this is List) this[0] else iterator().next())
            else -> toMap(LinkedHashMap<K, V>(mapCapacity(size)))
        }
    }
    return toMap(LinkedHashMap<K, V>()).optimizeReadOnlyMap()
}
val strings = listOf("a", "bb", "ccc")
val map = strings.map { it to it.length }.toMap()
public static <T, E> Map<E, T> toLinkedHashMap(List<T> list, Function<T, E> someFunction) {
    return list.stream()
               .collect(Collectors.toMap(
                   someFunction, 
                   myObject -> myObject, 
                   (key1, key2) -> key1, 
                   LinkedHashMap::new)
               );
}


Map<String, MyObject> myObjectsByIdMap1 = toLinkedHashMap(
                listOfMyObjects, 
                MyObject::getSomeStringField()
);

Map<Integer, MyObject> myObjectsByIdMap2 = toLinkedHashMap(
                listOfMyObjects, 
                MyObject::getSomeIntegerField()
);