Java 8将<T>列入Map <K,V>

Shu*_*rok 5 java lambda java-8 java-stream

我想将对象列表转换为Map,其中Map的键和值作为List中Object的属性.

这里转换的Java 7片段:

private Map<String, Child> getChildren(List<Family> families  ) {
        Map<String, Child> convertedMap = new HashMap<String, Child>();

        for (Family family : families) {
            convertedMap.put(family.getId(), family.getParent().getChild());
        }
        return convertedMap;
    }
Run Code Online (Sandbox Code Playgroud)

Jas*_*son 11

它应该类似于......

Map<String, Child> m = families.stream()
    .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild()));
Run Code Online (Sandbox Code Playgroud)


Stu*_*rks 9

杰森给出了一个不错的答案(+1),但我应该指出它与OP的Java 7代码有不同的语义.如果输入列表中的两个族实例具有重复的ID,则该问题与行为有关.也许他们保证是独一无二的,在这种情况下没有区别.但是,如果存在重复项,则使用OP的原始代码,Family列表中的后面将覆盖Family具有相同ID的列表中较早的映射条目.

使用Jason的代码(如下所示,略有修改):

Map<String, Child> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild()));
}
Run Code Online (Sandbox Code Playgroud)

如果有任何重复的键,Collectors.toMap操作将抛出IllegalStateException.这有点不愉快,但至少它会通知您存在重复,而不是可能会以静默方式丢失数据.规则Collectors.toMap(keyMapper, valueMapper)是您需要确保键映射器函数为流的每个元素返回唯一键.

你需要做些什么 - 如果有的话 - 取决于问题领域.一种可能性是使用三个arg版本:Collectors.toMap(keyMapper, valueMapper, mergeFunction).这指定了在重复的情况下调用的额外函数.如果您希望以后的条目覆盖之前的条目(与原始Java 7代码匹配),您可以这样做:

Map<String, Child> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.toMap(Family::getId, f -> f.getParent().getChild(),
                                                 (child1, child2) -> child2));
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是为每个家庭建立一个儿童名单,而不是只有一个孩子.您可以编写一个更复杂的合并函数,该函数为第一个子项创建一个列表,并为第二个子项和后续子项附加到此列表中.这很常见,有一个特殊的groupingBy收集器可以自动执行此操作.这将产生按ID分组的家庭列表.我们不想要一个系列列表,而是想要一个子列表,所以我们添加一个下游映射操作来从一个系列映射到一个子系列,然后将这些子系统收集到一个列表中.代码如下所示:

Map<String, List<Child>> getChildren(List<Family> families) {
    return families.stream()
        .collect(Collectors.groupingBy(Family::getId,
                    Collectors.mapping(f -> f.getParent().getChild(),
                        Collectors.toList())));
}
Run Code Online (Sandbox Code Playgroud)

请注意,返回类型已从更改Map<String, Child>Map<String, List<Child>>.