這是對最近作的一個項目,其中一個知識點的總結。java
真實的業務場景就不說了,我來模擬下業務場景,足夠說明問題就好了。函數
假設我有個對象,存儲人員的基本信息,以下:測試
@AllArgsConstructor @Data @ToString public class PersonInfo { private String name; private int age; private int sex; //0表示男性,1表示女性 }
添加一些測試數據,code
List<PersonInfo> personInfoList = new ArrayList<>(); personInfoList.add(new PersonInfo("tom", 32, 1)); personInfoList.add(new PersonInfo("jerry", 30, 1)); personInfoList.add(new PersonInfo("alice", 15, 0)); personInfoList.add(new PersonInfo("jack", 23, 1)); personInfoList.add(new PersonInfo("aya", 32, 0));
打印下看看,對象
personInfoList.forEach(e -> System.out.println(e));
PersonInfo(name=tom, age=32, sex=1) PersonInfo(name=jerry, age=30, sex=1) PersonInfo(name=alice, age=15, sex=0) PersonInfo(name=jack, age=23, sex=1) PersonInfo(name=aya, age=32, sex=0)
咱們能夠看到,打印的順序和咱們添加的順序是同樣的。接口
如今咱們有個需求,按照性別進行分組。get
這個也不難,在 java8 環境下咱們可使用stream流的groupingBy
很容易的實現,因而就有了下面的代碼,hash
Map<Integer, List<PersonInfo>> map = personInfoList.stream().collect(Collectors.groupingBy(PersonInfo::getSex));
groupingBy
實現相似SQL語句的「Group By」字句功能,實現根據一些屬性進行分組並把結果存在Map實例。io
打印結果看看是怎樣的,java8
map.forEach((key, value) -> System.out.println(key + ": " + value));
0: [PersonInfo(name=alice, age=15, sex=0), PersonInfo(name=aya, age=32, sex=0)] 1: [PersonInfo(name=tom, age=32, sex=1), PersonInfo(name=jerry, age=30, sex=1), PersonInfo(name=jack, age=23, sex=1)]
結果確實是按照要求分組了,可是PersonInfo對象的順序和咱們以前添加的順序不同了,在有些業務場景下,這種結果每每是不容許的。(好比分頁查詢等)
爲何順序會亂的?
咱們先來看看這個map是哪一個類型的,
System.out.println(map.getClass().getSimpleName());
打印出來的結果是 HashMap
。
這個就解釋了爲啥順序被打亂了, HashMap
在存儲是數據時,是先用key作hash計算,而後根據hash的結果決定這條數據的位置,由於hash自己是無序的,致使了讀出的順序是亂的。
知道了緣由後,那就很容易想到解決方案了, groupingBy
有一個重載的方法,容許咱們指定map進行操做,
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream)
注意看第二個參數, Supplier
是java8提供的一中函數接口類型,用於提供一個對象, 根據尖括號裏的定義,這裏須要提供一個Map
類型的對象。
另外咱們知道HashMap
和LinkedHashMap
的區別是後者經過雙向鏈表保證數據插入的順序和訪問的順序一致。 因而就有了下面的代碼,
Map<Integer, List<PersonInfo>> map = personInfoList.stream().collect(Collectors.groupingBy(PersonInfo::getSex, LinkedHashMap::new, Collectors.toList()));
打印的結果是,
1: [PersonInfo(name=tom, age=32, sex=1), PersonInfo(name=jerry, age=30, sex=1), PersonInfo(name=jack, age=23, sex=1)] 0: [PersonInfo(name=alice, age=15, sex=0), PersonInfo(name=aya, age=32, sex=0)]
能夠看到打印的順序和原來的list順序是同樣的。