当前位置: 首页 > 知识库问答 >
问题:

collectors.tomap()和collectors.groupingby()收集到映射中的差异

孟华晖
2023-03-14

我想从列表中创建一个映射并在映射中使用相同的parentId映射列表中的所有条目,如映射
我使用了Collectors.tomap()但它不编译:

Map<Long, List<Point>> pointByParentId = chargePoints.stream()
    .collect(Collectors.toMap(Point::getParentId, c -> c));

共有1个答案

韩善
2023-03-14

TLDR:

若要收集到按键包含单个值的映射中(映射 ),请使用Collectors.tomap()
若要收集到按键包含多个值的映射(映射 ),请使用Collectors.GroupingBy()

collectors.tomap()

chargePoints.stream().collect(Collectors.toMap(Point::getParentId, c -> c));

返回的对象将具有map 类型。
查看正在使用的collectors.tomap()函数:

Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper)

它返回一个收集器,结果为映射 ,其中ku是传递给方法的两个函数的返回类型。在您的示例中,point::GetParentId是长的,而C指的是point。而在应用collection()时返回的map

而且这种行为是预期的,因为Collectors.tomap()javadoc声明:

如果映射的键可能有重复项,您可以使用tomap(Function,Function,BinaryOperator)重载,但它不会真正解决您的问题,因为它不会对具有相同parentId元素进行分组。它只是提供了一种方法,使两个元素不具有相同的parentId

Collectors.GroupingBy()

为了达到您的要求,您应该使用collectors.groupingby(),它的行为和方法声明更适合您的需要:

public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier) 

指定为:

返回一个收集器,该收集器对类型为T的输入元素执行“GROUP BY”操作,根据分类函数对元素进行分组,并在映射中返回结果。

该方法采用function
在您的情况下,function参数是point(流的type),并且返回point.getParentId(),因为您希望通过parentId值对元素进行分组。

Map<Long, List<Point>> pointByParentId = 
                       chargePoints.stream()
                                   .collect(Collectors.groupingBy( p -> p.getParentId())); 

或使用方法引用:

Map<Long, List<Point>> pointByParentId = 
                       chargePoints.stream()
                                   .collect(Collectors.groupingBy(Point::getParentId));

Collectors.GroupingBy():进一步

实际上,groupingby()收集器比实际示例更进一步。Collectors.GroupingBy(Function<?super T,?extends k>classifier)方法最终只是一种将收集的映射的值存储在列表中的方便方法。
要将映射的值存储在列表之外的其他东西中或存储特定计算的结果,GroupingBy(Function<?super T,?extends k>classifier,collector<?super T,?extends k>classifier,collector<?super T,a,d>downdown)应该会引起您的兴趣。

例如:

Map<Long, Set<Point>> pointByParentId = 
                       chargePoints.stream()
                                   .collect(Collectors.groupingBy(Point::getParentId, toSet()));

因此,除了所问的问题之外,您应该考虑groupingby()作为一种灵活的方法来选择要存储到收集的map中的值,而tomap()绝对不是这样。

 类似资料:
  • 假设你有一张这样的物体地图(尽管想象它更大): rtype=133,有两个! 我想对Streams做的是这样的: 我在理解Collectors&groupBy的工作原理时遇到了一些麻烦,但我想这可能会用于本例。 在Java streams API中进行编码的正确方法是什么? 我很难找到类似的地图例子(人们在他们的例子中更多地使用列表)

  • 我正在使用Java8lambda,并希望使用返回。我所能想到的最好方法是使用等于的虚拟和调用以下

  • 我有两个列表,我必须从它们创建一个地图。首先,我在迭代for loop,其次,我想通过一个stream和collect来映射,但我不知道在这种情况下如何使用collectors.tomap。有可能吗?

  • 我试图使用流API代替循环,并有以下问题。 我有一个方法,它接受一个Enum并返回一个SortedMap。我将每个映射存储在一个列表中,但是我现在希望将每个SortedMap存储在一个映射中,Enum名称为键,从返回的SortedMap作为值,如何使用流API执行此操作? 当前工作列表方法 我使用收集器的错误尝试。toMap。。 工作回路,工作回路

  • 以下代码 由IntelliJ转换为: 可以缩短为 这两个流版本不编译。 IntelliJ,暗示值中的i存在问题[i]: 不兼容的类型 必需:int找到:java。lang.对象 编译器抱怨: 错误:(35,17)java:接口java中的方法collect。util。流动IntStream不能应用于给定类型 必需:java。util。作用供应商,爪哇。util。作用ObjIntConsumer,j