Java8 Stream 集合 過濾 排序 分組 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)]
如果本文對您有幫助,就點個贊👍吧