问题
我的需求是查询出来一组数据后,按照其中的某个属性进行groupBy
分组,分组后要保证顺序不变。
但是实际用groupBy进行分组后,返回的数据是杂乱无章的,没有按照原来list 的顺序返回。
排查
首先去api
中查找问题原因,查看Java
的java.util.stream
包 Collectors
类 groupingBy
方法实现,结果如下:
//一个参数
public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier) {
return groupingBy(classifier, toList());
}
//实际调用方法
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream);
}
//两个参数
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream);
}
//三个参数
public static <T, K, D, A, M extends Map<K, D>>
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream) {
Supplier<A> downstreamSupplier = downstream.supplier();
BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
downstreamAccumulator.accept(container, t);
};
BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
@SuppressWarnings("unchecked")
Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
}
else {
@SuppressWarnings("unchecked")
Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
Function<Map<K, A>, M> finisher = intermediate -> {
intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
@SuppressWarnings("unchecked")
M castResult = (M) intermediate;
return castResult;
};
return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
}
}
可以发现 groupingBy
调用是内部自己创建了一 HashMap(HashMap::new)
。因为 HashMap
,是无无序的,是根据key
的hashcode
进行hash
,然后放入指定位置,所以按照一定顺序put
进HashMap
时与遍历出HashMap
的顺序不同。
因此我们直接调用三个参数的groupingBy
方法mapFactory
,传入有顺序的Map(LinkedHashMap)
就可以了。
示例
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < 3; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("index", 3);
map.put("category", "类别3");
map.put("other", i);
list.add(map);
}
for (int i = 0; i < 3; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("index", 1);
map.put("category", "类别1");
map.put("other", i);
list.add(map);
}
for (int i = 0; i < 3; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("index", 2);
map.put("category", "类别2");
map.put("other", i);
list.add(map);
}
for (int i = 3; i < 6; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("index", 2);
map.put("category", "类别1");
map.put("other", i);
list.add(map);
}
System.out.println(list);
Map<String, List<Map<String, Object>>> step1 = list.stream().collect(Collectors.groupingBy(o -> {
return o.get("category").toString();
}));
System.out.println(step1);
// 手动控制排序方式
Map<String, List<Map<String, Object>>> step2 = list.stream().sorted(Comparator.comparingInt(o -> {
return -(int) o.get("index");
})).collect(Collectors.groupingBy(o -> {
return o.get("category").toString();
}, LinkedHashMap::new, Collectors.toList()));
System.out.println(step2);
}
}
运行结果
[{other=0, index=3, category=类别3}, {other=1, index=3, category=类别3}, {other=2, index=3, category=类别3}, {other=0, index=1, category=类别1}, {other=1, index=1, category=类别1}, {other=2, index=1, category=类别1}, {other=0, index=2, category=类别2}, {other=1, index=2, category=类别2}, {other=2, index=2, category=类别2}, {other=3, index=2, category=类别1}, {other=4, index=2, category=类别1}, {other=5, index=2, category=类别1}]
{类别1=[{other=0, index=1, category=类别1}, {other=1, index=1, category=类别1}, {other=2, index=1, category=类别1}, {other=3, index=2, category=类别1}, {other=4, index=2, category=类别1}, {other=5, index=2, category=类别1}], 类别3=[{other=0, index=3, category=类别3}, {other=1, index=3, category=类别3}, {other=2, index=3, category=类别3}], 类别2=[{other=0, index=2, category=类别2}, {other=1, index=2, category=类别2}, {other=2, index=2, category=类别2}]}
{类别3=[{other=0, index=3, category=类别3}, {other=1, index=3, category=类别3}, {other=2, index=3, category=类别3}], 类别2=[{other=0, index=2, category=类别2}, {other=1, index=2, category=类别2}, {other=2, index=2, category=类别2}], 类别1=[{other=3, index=2, category=类别1}, {other=4, index=2, category=类别1}, {other=5, index=2, category=类别1}, {other=0, index=1, category=类别1}, {other=1, index=1, category=类别1}, {other=2, index=1, category=类别1}]}