I want to create a Map
from a List
of Points
and have inside the map all entries from the list mapped with the same parentId such as Map<Long, List<Point>>
。
我使用了 Collectors.toMap()
但它没有编译:
Map<Long, List<Point>> pointByParentId = chargePoints.stream()
.collect(Collectors.toMap(Point::getParentId, c -> c));
原文由 Tim Schwalbe 发布,翻译遵循 CC BY-SA 4.0 许可协议
TLDR :
要收集到包含单个值的
Map
键(Map<MyKey,MyObject>
),请使用Collectors.toMap()
。要收集到包含多个键值的
Map
(Map<MyKey, List<MyObject>>
),请使用Collectors.groupingBy()
。收集器.toMap()
通过写作:
返回的对象将具有
Map<Long,Point>
类型。查看您正在使用的
Collectors.toMap()
函数:It returns a
Collector
with as resultMap<K,U>
whereK
andU
are the type of return of the two functions passed to the method.在您的情况下,Point::getParentId
是 Long 而c
指的是Point
。而Map<Long,Point>
在应用collect()
时返回。正如 Collectors.toMap() javadoc 所述,这种行为是意料之中的:
但是,如果映射的键包含重复项(根据
Object.equals(Object)
),则会抛出IllegalStateException
这可能是您的情况,因为您将根据特定属性对
Point
进行分组:parentId
。如果映射的键可能重复,您可以使用
toMap(Function, Function, BinaryOperator)
重载,但它不会真正解决您的问题,因为它不会将具有相同parentId
的元素分组。它只会提供一种方法,使两个元素不具有相同的parentId
。收集器.groupingBy()
为了达到您的要求,您应该使用
Collectors.groupingBy()
其行为和方法声明更适合您的需要:它被指定为:
该方法采用
Function
。In your case, the
Function
parameter isPoint
(thetype
of Stream) and you returnPoint.getParentId()
as you want to group elements byparentId
值。所以你可以写:
或者使用方法参考:
Collectors.groupingBy() :更进一步
实际上
groupingBy()
收集器比实际示例走得更远。Collectors.groupingBy(Function<? super T, ? extends K> classifier)
方法最终只是一种方便的方法,用于将收集到的值Map
存储在List
中。要将 --- 的值存储在不同于
List
Map
的其他事物中,或者存储特定计算的结果,groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
,你应该感兴趣。例如 :
因此,除了提出的问题之外,您应该考虑
groupingBy()
作为选择要存储到收集的值的灵活方式Map
,最终toMap()
不是.