Java8 Stream 集合 過濾 排序 分組 List轉Map

Stream流

什麼是流

Stream是Java8新增的API,高深的概念理論不去說了,就像把一個數據集合,放到工廠加工流水線的傳送帶上,經過不同工種工人的加工,到傳送帶的盡頭得到了你想要的數據。它的寫法有點像SQL語句,可以讓程序員處理集合數據時,更加簡短和明瞭。

準備數據

public class JavaLambdaTest {
    private static List<Pig> pigList = new ArrayList<>();

    public static void main(String[] args) {
        pigList.add(new Pig(1, "豬爸爸", 27, "M", false));
        pigList.add(new Pig(2, "豬媽媽", 28, "F", true));
        pigList.add(new Pig(3, "喬治", 2, "M", false));
        pigList.add(new Pig(4, "佩奇", 5, "F", false));
}

@Data
@AllArgsConstructor
class Pig {
    private int id;
    private String name;
    private Integer age;
    private String gender;
    private boolean valid;
}

創建流

Stream<Pig> pigStream = pigList.stream();

遍歷流

pigStream.forEach(pig -> System.out.println(pig));

Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)
Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)
Pig(id=3, name=喬治, age=2, gender=M, valid=false)
Pig(id=4, name=佩奇, age=5, gender=F, valid=false)

流只能使用一次

一個流創建好後,只能使用一次,如果需要再次使用,需要從源數據集合再次創建

#第一句可執行
pigStream.forEach(pig -> System.out.println(pig));

#第二句會報錯 stream has already been operated upon or closed
pigStream.forEach(pig -> System.out.println(pig));

過濾

在這裏插入圖片描述

查詢age>2的數據:

Stream<Pig> pigStream1 = pigList.stream().filter(pig -> pig.getAge() > 2);

這裏的filter方法接收的是Predicate<? super T> predicate,這個返回boolean類型。

查詢有效的(valid = true)數據:

Stream<Pig> pigStream2 = pigList.stream().filter(Pig::isValid);

上面語句Pig::isValid,是行爲參數化,isValid是Pig的boolean方法。

Stream轉List

上面也說了Stream只能使用一次,加上.collect(toList())後轉成List,可繼續使用過濾後的數據了

import static java.util.stream.Collectors.toList;

List<Pig> pigList1 = pigList.stream().filter(pig -> pig.getAge() > 2).collect(toList());        

排序

想想Java8之前的集合排序多拗口,現在Java8寫排序,所寫即所想,非常明瞭

age升序

import static java.util.Comparator.comparing;

pigList.sort(comparing(Pig::getAge));

age降序

pigList.sort(comparing(Pig::getAge).reversed());

根據性別gender升序排,再以年齡age升序

pigList.sort(comparing(Pig::getGender).thenComparing(Pig::getAge));

===Comparator 根據性別升序排,再以年齡升序 ===
Pig(id=4, name=佩奇, age=5, gender=F, valid=false)
Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)
Pig(id=3, name=喬治, age=2, gender=M, valid=false)
Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)

根據性別gender升序排,再以年齡age降序

pigList.sort(comparing(Pig::getGender).thenComparing(comparing(Pig::getAge).reversed()));       

===Comparator 根據性別gender升序排,再以年齡age降序 ===
Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)
Pig(id=4, name=佩奇, age=5, gender=F, valid=false)
Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)
Pig(id=3, name=喬治, age=2, gender=M, valid=false)

這個很重要,不能寫錯,下面是錯誤的的寫法

#錯誤的寫法,這個reversed()會將之前的排序再反轉
pigList.sort(comparing(Pig::getGender).thenComparing(Pig::getAge).reversed());

根據性別gender降序排,再以年齡age升序

pigList.sort(comparing(Pig::getGender).reversed().thenComparing(Pig::getAge));

===Comparator 根據性別gender降序排,再以年齡age升序 ===
Pig(id=3, name=喬治, age=2, gender=M, valid=false)
Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)
Pig(id=4, name=佩奇, age=5, gender=F, valid=false)
Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)

根據性別gender降序排,再以年齡age降序

pigList.sort(comparing(Pig::getGender).thenComparing(Pig::getAge).reversed());

===Comparator 根據性別gender降序排,再以年齡age降序 ===
Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)
Pig(id=3, name=喬治, age=2, gender=M, valid=false)
Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)
Pig(id=4, name=佩奇, age=5, gender=F, valid=false)

Limit

通常排序後,希望獲取前面幾個數據,可以使用Limit
在這裏插入圖片描述

pigList.sort(comparing(Pig::getAge));
Stream<Pig> topPigs = pigList.stream().limit(2);
topPigs.forEach(a -> System.out.println(a));

Count

獲取Stream的元素個數

Long count = pigList.stream().filter(a -> a.getAge() > 10).count();

Map(映射)

對於Stream中包含的元素使用給定的轉換函數進行轉換操作,新生成的Stream只包含轉換生成的元素。
在這裏插入圖片描述

獲取性別的集合,返回List

List<String> genderList = pigList.stream().map(Pig::getGender).collect(toList());

M
F
M
F

配合distinct獲取去重的性別集合

在這裏插入圖片描述

List<String> genderList2 = pigList.stream().map(Pig::getGender).distinct().collect(toList()); 
       
===distinct()===
M
F

配合toSet獲取去重的性別集合

Set<String> genderSet = pigList.stream().map(Pig::getGender).collect(toSet());

===toSet()===
F
M     

拼接字符串

String字符串在java中是不可變的,如果在for循環裏用+拼接字符串,會生成很多字符串。 joining在內部使用了StringBuilder來把生成的字符串逐個追加起來。

String names = pigList.stream().map(Pig::getName).collect(joining(","));
System.out.println(names);

List轉Map<Integer, Object>

把id作爲key,pig對象作爲value存儲

Map<Integer, Pig> mapById = pigList.stream().collect(Collectors.toMap(Pig::getId, a -> a, (k1, k2) -> k1));
mapById.forEach((key, value) -> System.out.println(key + " -> " + value.toString()));

=== List轉Map<Integer, Object>===
1 -> Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)
2 -> Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)
3 -> Pig(id=3, name=喬治, age=2, gender=M, valid=false)
4 -> Pig(id=4, name=佩奇, age=5, gender=F, valid=false)

List轉Map<String, Object>

上面id是唯一的,如果按照性別呢?

如果gender重複就用第一個
Map<String, Pig> mapByGender = pigList.stream().collect(Collectors.toMap(Pig::getGender, a -> a, (k1, k2) -> k1));
mapByGender.forEach((key, value) -> System.out.println(key + " -> " + value.toString()));

=== List轉Map<String, Object>===
F -> Pig(id=4, name=佩奇, age=5, gender=F, valid=false)
M -> Pig(id=3, name=喬治, age=2, gender=M, valid=false)

List轉Map<String, ObjectList>,用分組(groupingBy)

這個分組功能在工作中非常常用

Map<String, List<Pig>> groupByGender = pigList.stream().collect(groupingBy(Pig::getGender));
groupByGender.forEach((key, value) -> System.out.println(key + " -> " + value.toString()));

=== List轉Map<String,  List<Object>>===
F -> [Pig(id=4, name=佩奇, age=5, gender=F, valid=false), Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)]
M -> [Pig(id=3, name=喬治, age=2, gender=M, valid=false), Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)]

分區(partitioningBy)

分區是分組的特殊情況:由一個謂詞(返回一個布爾值的函數)作爲分類函數,它稱分區函
數。分區函數返回一個布爾值,這意味着得到的分組Map的鍵類型是Boolean,於是它最多可以
分爲兩組——true是一組,false是一組。

Map<Boolean, List<Pig>> partitioningByGender = pigList.stream().collect(partitioningBy(Pig::isValid));
partitioningByGender.forEach((key, value) -> System.out.println(key + " -> " + value.toString()));

=== partitioningByGender===
false -> [Pig(id=3, name=喬治, age=2, gender=M, valid=false), Pig(id=4, name=佩奇, age=5, gender=F, valid=false), Pig(id=1, name=豬爸爸, age=27, gender=M, valid=false)]
true -> [Pig(id=2, name=豬媽媽, age=28, gender=F, valid=true)]

如果本文對您有幫助,就點個贊👍吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章