如何使用 java 8 将一组对象分组到排序列表中?
How to group a set of objects into sorted lists using java 8?
我想获取一组对象(在本例中为 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
对象的域,值是 属性 列表的列表。我现在想要的是对列表进行排序,以确保它们按字母顺序排列。有什么方法可以在同一个表达式中做到这一点吗?
一个想法是在 .stream()
之后添加 .sort()
,但这真的能保证有效吗?
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())));
当然你可以在收集之前对整个流进行排序:
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()
做同样的事情,但不能保证),然后在没有额外复制的情况下就地对结果列表进行排序(使用 stream().sorted().collect(toList())
你至少复制整个列表内容两次)。另请注意,<T>
参数必须声明为 extends Comparable<T>
。否则,您可能会错误地将此收集器用于不可比较的类型,该类型可以正常编译,但会导致运行时错误。
我想获取一组对象(在本例中为 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
对象的域,值是 属性 列表的列表。我现在想要的是对列表进行排序,以确保它们按字母顺序排列。有什么方法可以在同一个表达式中做到这一点吗?
一个想法是在 .stream()
之后添加 .sort()
,但这真的能保证有效吗?
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())));
当然你可以在收集之前对整个流进行排序:
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()
做同样的事情,但不能保证),然后在没有额外复制的情况下就地对结果列表进行排序(使用 stream().sorted().collect(toList())
你至少复制整个列表内容两次)。另请注意,<T>
参数必须声明为 extends Comparable<T>
。否则,您可能会错误地将此收集器用于不可比较的类型,该类型可以正常编译,但会导致运行时错误。