Java8Stream进⾏groupby不会打乱顺序
问题背景:
需求分析 ,对查询出来的数据,进⾏按类型,名称,开始时间进⾏排序,排序完之后需要进⾏分组,但是在groupBy分组的时候,顺序却是乱的?并没有按照⾃⼰进⾏排序的list进⾏返回。
带问题排查
sort排序没问题,问题出在groupBy⾝上,看看groupby问什么会⽆序。查看源码
/**
* Returns a {@code Collector} implementing a "group by" operation on
* input elements of type {@code T}, grouping elements according to a
* classification function, and returning the results in a {@code Map}.
*
* <p>The classification function maps elements to some key type {@code K}.
* The collector produces a {@code Map<K, List<T>>} whose keys are the
* values resulting from applying the classification function to the input
* elements, and whose corresponding values are {@code List}s containing the
* input elements which map to the associated key under the classification
* function.
*
* <p>There are no guarantees on the type, mutability, serializability, or
* thread-safety of the {@code Map} or {@code List} objects returned.
* @implSpec
* This produces a result similar to:
* <pre>{@code
*    groupingBy(classifier, toList());
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent.  For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation.  If
* preservation of the order in which elements appear in the resulting {@code Map}
* collector is not required, using {@link #groupingByConcurrent(Function)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param classifier the classifier function mapping input elements to keys
* @return a {@code Collector} implementing the group-by operation
*
* @see #groupingBy(Function, Collector)
* @see #groupingBy(Function, Supplier, Collector)
* @see #groupingByConcurrent(Function)
*/
public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier) {
return groupingBy(classifier, toList());
}
/**
* Returns a {@code Collector} implementing a cascaded "group by" operation
* on input elements of type {@code T}, grouping elements according to a
* classification function, and then performing a reduction operation on
* the values associated with a given key using the specified downstream
* {@code Collector}.
groupby是什么函数*
* <p>The classification function maps elements to some key type {@code K}.
* The downstream collector operates on elements of type {@code T} and
* produces a result of type {@code D}. The resulting collector produces a
* {@code Map<K, D>}.
* {@code Map<K, D>}.
*
* <p>There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {@code Map} returned.
*
* <p>For example, to compute the set of last names of people in each city:
* <pre>{@code
*    Map<City, Set<String>> namesByCity
*        = people.stream().collect(groupingBy(Person::getCity,
*                                              mapping(Person::getLastName, toSet())));
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent.  For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation.  If
* preservation of the order in which elements are presented to the downstream
* collector is not required, using {@link #groupingByConcurrent(Function, Collector)}
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param <A> the intermediate accumulation type of the downstream collector
* @param <D> the result type of the downstream reduction
* @param classifier a classifier function mapping input elements to keys
* @param downstream a {@code Collector} implementing the downstream reduction
* @return a {@code Collector} implementing the cascaded group-by operation
* @see #groupingBy(Function)
*
* @see #groupingBy(Function, Supplier, Collector)
* @see #groupingByConcurrent(Function, Collector)
*/
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);
}
/**
* Returns a {@code Collector} implementing a cascaded "group by" operation
* on input elements of type {@code T}, grouping elements according to a
* classification function, and then performing a reduction operation on
* the values associated with a given key using the specified downstream
* {@code Collector}.  The {@code Map} produced by the Collector is created
* with the supplied factory function.
*
* <p>The classification function maps elements to some key type {@code K}.
* The downstream collector operates on elements of type {@code T} and
* produces a result of type {@code D}. The resulting collector produces a
* {@code Map<K, D>}.
*
* <p>For example, to compute the set of last names of people in each city,
* where the city names are sorted:
* <pre>{@code
*    Map<City, Set<String>> namesByCity
*        = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
*                                              mapping(Person::getLastName, toSet())));
* }</pre>
*
* @implNote
* The returned {@code Collector} is not concurrent.  For parallel stream
* pipelines, the {@code combiner} function operates by merging the keys
* from one map into another, which can be an expensive operation.  If
* preservation of the order in which elements are presented to the downstream
* collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}    * may offer better parallel performance.
* may offer better parallel performance.
*
* @param <T> the type of the input elements
* @param <K> the type of the keys
* @param <A> the intermediate accumulation type of the downstream collector
* @param <D> the result type of the downstream reduction
* @param <M> the type of the resulting {@code Map}
* @param classifier a classifier function mapping input elements to keys
* @param downstream a {@code Collector} implementing the downstream reduction
* @param mapFactory a function which, when called, produces a new empty
*                  {@code Map} of the desired type
* @return a {@code Collector} implementing the cascaded group-by operation
*
* @see #groupingBy(Function, Collector)
* @see #groupingBy(Function)
* @see #groupingByConcurrent(Function, Supplier, Collector)
*/
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 = quireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
A container = mputeIfAbsent(key, k -> ());
downstreamAccumulator.accept(container, t);
};
BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstreambiner());
@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 -> {
@SuppressWarnings("unchecked")
M castResult = (M) intermediate;
return castResult;
};
return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
}
}
能够看到groupBy是有三个函数,第⼀个函数⼀个参数进⾏classifier,第⼆个为两个参数 可以看到HaseMap
groupingBy(classifier, HashMap::new, downstream);
HaseMap的排序是按haseCode进⾏的排序,是根据key的hashcode进⾏hash,然后放⼊对应的地址。所以在按照⼀定顺序put进HashMap中,然后遍历出HashMap的顺序跟put的顺序不同。
第三个函数的mapFactory,我们可以进⾏传递LinkedHashMap确保有序
groupingBy(User::getName, LinkedHashMap::new, List())
HashMap和LinkedHashMap区别:
LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
HashMap⽆序;LinkedHashMap有序,可分为插⼊顺序和访问顺序两种。如果是访问顺序,那put和g
et操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插⼊)。
LinkedHashMap存取数据,还是跟HashMap⼀样使⽤的Entry[]的⽅式,双向链表只是为了保证顺序。
LinkedHashMap是线程不安全的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。