我想获取一组对象(在这种情况下为ObjectInstance
),我想用一个属性对它们进行分组,并将结果列表排序在另一个属性上。
Set<ObjectInstance> beans = server.queryMBeans(null, null);
Map<String, List<String>> beansByDomain = beans.stream()
.collect(groupingBy( (ObjectInstance oi) -> oi.getObjectName().getDomain(),
mapping((ObjectInstance oi) -> oi.getObjectName().getCanonicalKeyPropertyListString(),
toList() )));
上面的表达式创建了正确的数据结构:Map
,其中键是ObjectInstance
个对象的域,值是属性列表的列表。我想要的是现在对列表进行排序,以确保它们按字母顺序排列。有没有办法在同一个表达式中执行此操作?
一个想法是在.sort()
之后立即添加.stream()
,但这是否真的有效?
答案 0 :(得分:9)
List<String> beansByDomain = beans.stream()
.collect(groupingBy( (ObjectInstance oi) -> oi.getObjectName().getDomain(),
mapping((ObjectInstance oi) -> oi.getObjectName().getCanonicalKeyPropertyListString(),
collectingAndThen(toList(), (l -> l.stream().sorted().collect(toList()))) )));
您可以提取收集器以使代码更具可读性:
public static <T> Collector<T,?,List<T>> toSortedList() {
return Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream().sorted().collect(toList()));
}
List<String> beansByDomain = beans.stream()
.collect(groupingBy( (ObjectInstance oi) -> oi.getObjectName().getDomain(),
mapping((ObjectInstance oi) -> oi.getObjectName().getCanonicalKeyPropertyListString(),
toSortedList())));
答案 1 :(得分:3)
当然,您可以在收集之前对整个流进行排序:
Map<String, List<String>> beansByDomain = beans.stream()
.map(ObjectInstance::getObjectName)
.sorted(Comparator.comparing(ObjectName::getCanonicalKeyPropertyListString))
.collect(groupingBy(ObjectName::getDomain,
mapping(ObjectName::getCanonicalKeyPropertyListString,
toList() )));
请注意,我添加了.map(ObjectInstance::getObjectName)
步骤,因为您不需要ObjectInstance
中的任何其他内容。这样可以很好地工作,但我无法预测它是否比单独排序每个结果列表更快。
如果您更喜欢单独的toSortingList()
收集器(如在@JeanLogeart答案中),可以像这样进行优化:
public static <T extends Comparable<T>> Collector<T,?,List<T>> toSortedList() {
return collectingAndThen(toCollection(ArrayList::new),
(List<T> l) -> {l.sort(Comparator.naturalOrder()); return l;});
}
此处我们明确收集到ArrayList
(toList()
执行相同操作,但不保证),然后对结果列表进行排序而不进行额外复制(使用{{1}你复制整个列表内容至少两次)。另请注意,stream().sorted().collect(toList())
参数必须声明为<T>
。否则,您可能会错误地将此收集器用于非可比较类型,这将很好地编译,但会导致运行时错误。