我希望从List of Points创建一个Points,并将列表中的所有条目都用相同的parentId (如Map<Long, List<Point>> )映射。
我使用了Collectors.toMap(),但它没有编译:
Map<Long, List<Point>> pointByParentId = chargePoints.stream()
.collect(Collectors.toMap(Point::getParentId, c -> c));发布于 2017-07-21 07:35:31
TLDR :
若要收集到包含单个键值的Map (Map<MyKey,MyObject>),请使用Collectors.toMap()。
若要收集到包含多个键值的Map (Map<MyKey, List<MyObject>>),请使用Collectors.groupingBy()。
Collectors.toMap()
以书面形式:
chargePoints.stream().collect(Collectors.toMap(Point::getParentId, c -> c));返回的对象将具有Map<Long,Point>类型。
查看您正在使用的Collectors.toMap()函数:
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)它返回一个结果为Collector的Map<K,U>,其中K和U是传递给方法的两个函数的返回类型。在您的例子中,Point::getParentId是长的,c指的是Point。而Map<Long,Point>在应用collect()时返回。
这种行为是Collectors.toMap() javadoc声明的结果:
返回一个
Collector,它将元素累加到一个Map中,该Map的键和值是将提供的映射函数应用于输入元素的结果。
但是,如果映射的键包含重复项(根据Object.equals(Object)),则抛出一个IllegalStateException
这可能是您的情况,因为您将根据一个特定的属性:Point:parentId对parentId进行分组。
如果映射的键可能有重复项,则可以使用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“操作的收集器,根据分类函数对元素进行分组,并在Map中返回结果。
该方法采用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)方法只是一个方便的方法,可以将收集到的Map值存储在List中。
要将Map的值存储在List以外的其他东西中,或者存储特定计算的结果,groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)应该会让您感兴趣。
例如:
Map<Long, Set<Point>> pointByParentId =
chargePoints.stream()
.collect(Collectors.groupingBy(Point::getParentId, toSet()));因此,除了提出的问题之外,您应该考虑groupingBy()是一种灵活的方法,可以选择您想要存储到所收集的Map中的值,确切地说,toMap()不是。
发布于 2017-07-21 07:23:27
Collectors.groupingBy正是您想要的,它从您的输入集合中创建了一个Map,使用为它的键提供的Function创建了一个条目,并作为它的值使用关联的键创建了一个点列表。
Map<Long, List<Point>> pointByParentId = chargePoints.stream()
.collect(Collectors.groupingBy(Point::getParentId));发布于 2017-07-21 07:25:55
下面的代码可以完成这些工作。Collectors.toList()是默认的,所以您可以跳过它,但是如果需要Map<Long, Set<Point>> Collectors.toSet()的话。
Map<Long, List<Point>> map = pointList.stream()
.collect(Collectors.groupingBy(Point::getParentId, Collectors.toList()));https://stackoverflow.com/questions/45231351
复制相似问题