在jdk1.8之前,我們對于集合的處理都是比較麻煩的,比如:做一次過濾,就會在代碼中使用for進行處理。jdk1.8後引入了Stream API來處理集合,使其變得簡單。
1、Stream簡介
Stream:流,可以對集合進行操作,比如:顧慮,合并等,是一種高效且易于使用處理資料的方法。
在Stream操作中分為三個步驟:
1、建立Stream流:比如:Stream.of()等
2、中間操作:即處理Stream流,比如:filter,map等
3、終止操作:即結束Stream流,傳回操作結果,比如:collect(Collectors.toList())
在操作Stream時,Stream自己不會存儲元素,不會改變原來對象,會延遲執行,隻會在需要結果時才執行。
2、Stream常用方法
準備工作,建立一個專家實體,便于進行方法操作。
/**
* @author: jiangjs
* @description:
* @date: 2022/7/15 15:37
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Expert {
private String name;
private String gender;
private Integer age;
}
複制代碼
建立一個集合:
List<Expert> experts = Arrays.asList(
new Expert("jiashn","男",20),
new Expert("張三-zhangsan","女",21),
new Expert("王五-wangwu","女",26),
new Expert("李四-lisi","男",24),
new Expert("李四-lisi","男",24));
複制代碼
2.1 建立Stream
stream()或parallelStream() :集合通過stream()可以建立順序流,parallelStream()建立并行流。
experts.stream()
experts.parallelStream()
複制代碼
Stream.of() :将數組轉化成Stream流。
Stream<Expert> expertStream = Stream.of(new Expert("趙一-zhaoyi", "男", 20),
new Expert("王定六-wangdingliu", "男", 21));
複制代碼
2.2 Stream中間操作
2.2.1 filter
filter(Predicate p) :用于過濾滿足條件的資料,例如:上述專家中查找年齡小于等于25歲的人員。
//過濾年齡小于等于25的人
List<Expert> filterExperts = experts.stream().filter(expert -> expert.getAge() <= 25).collect(Collectors.toList());
System.out.println("年齡小于等于25歲的人的資訊:" + filterExperts);
複制代碼
輸出:
年齡小于25歲的人的資訊:[Expert(name=jiashn, gender=男, age=20), Expert(name=張三-zhangsan, gender=女, age=21), Expert(name=李四-lisi, gender=男, age=24)]
2.2.2 map和flatMap
map(Function f) :将每個元素映射成新的元素,用于擷取集合中某個元素的資料資訊,例如:擷取所有專家的名字。
//擷取是以成員的名字資訊
String names = experts.stream().map(Expert::getName).collect(Collectors.joining(","));
System.out.println("所有人員的名稱:" + names);
複制代碼
輸出:
所有人員的名稱:jiashn,張三-zhangsan,王五-wangwu,李四-lisi
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) :将流中每個值換成另一個流,并将所有流彙成一個流。例如:拆分名字,并擷取名字資訊。
//拆分名字
List<String> splitName = experts.stream().flatMap(exp -> Stream.of(exp.getName().split("-")))
.collect(Collectors.toList());
System.out.println("拆分名字結果:" + splitName);
複制代碼
輸出:
拆分名字結果:[jiashn, 張三, zhangsan, 王五, wangwu, 李四, lisi]
2.2.3 sorted
sorted() :排序,預設是升序排序,會産生一個新的流
sorted(Comparator<? super T> comparator) :排序,按照比較器順序排序,會産生一個新的流。例如:按照年齡進行排序
//年齡排序,正序或倒序
List<Expert> sortInfo = experts.stream().sorted(Comparator.comparing(Expert::getAge))
.collect(Collectors.toList());
List<Expert> reversedInfo = experts.stream().sorted(Comparator.comparing(Expert::getAge).reversed())
.collect(Collectors.toList());
System.out.println("人員年齡排序(升序):" + sortInfo+";人員年齡排序(降序):"+reversedInfo);
複制代碼
輸出:
人員年齡排序(升序):[Expert(name=jiashn, gender=男, age=20), Expert(name=張三-zhangsan, gender=女, age=21), Expert(name=李四-lisi, gender=男, age=24), Expert(name=王五-wangwu, gender=女, age=26)];
人員年齡排序(降序):[Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24), Expert(name=張三-zhangsan, gender=女, age=21), Expert(name=jiashn, gender=男, age=20)]
在比較器中使用 .reversed() 實作排序降序。
2.2.4 distinct()
distinct() :去重,通過流所生成的hashCode()和equals()去除重複元素。例如:去重上面集合中的李四.
//去重
List<Expert> disExperts = experts.stream().distinct()
.collect(Collectors.toList());
System.out.println("去重:" + disExperts);
複制代碼
輸出:
去重:[Expert(name=jiashn, gender=男, age=20), Expert(name=張三-zhangsan, gender=女, age=21), Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24)]
2.2.5 limit、skip
limit(long maxSize) :截斷目前流,擷取不超過給定數量的元素。
skip(long n) :跳過元素,扔掉下标從0開始到n的元素的流,如果流中元素個數不超n個,則傳回一個空流,與limit()互補。例如:擷取下标從2開始的2個元素。
//截取記錄資訊
List<Expert> twoInfos = experts.stream().skip(2).limit(2).collect(Collectors.toList());
System.out.println("截取記錄:"+twoInfos);
複制代碼
輸出:
截取記錄:[Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24)]
我們也可以使用skip、limit的組合來對傳回回來的list資料進行分頁操作。
2.3 Stream終止操作
終端操作從流的流水線生成結果。
2.3.1 allMatch、anyMatch、noneMatch
allMatch(Predicate p) :檢查集合中所有元素是否與目前條件相比對。例如:驗證目前集合中元素性别是否都是男。
anyMatch(Predicate p) :檢查目前集合中是否存在元素與目前條件相比對。例如:驗證目前集合中元素是否存在性别男。
noneMatch(Predicate p) :檢查目前集合元素是否所有元素與目前條件不比對。例如:驗證目前集合所有元素性别都不為男。
//allMatch
boolean allMatch = experts.stream().allMatch(expert -> Objects.equals(expert.getGender(), "男"));
System.out.println("是否性别都為男:"+allMatch);
//anyMatch
boolean ageMatch = experts.stream().anyMatch(expert -> Objects.equals(expert.getGender(), "男"));
System.out.println("是否存在性别為男:"+ageMatch);
//noneMatch
boolean noneMatch = experts.stream().noneMatch(expert -> Objects.equals(expert.getGender(), "男"));
System.out.println("所有元素性别不為男:"+noneMatch);
複制代碼
輸出:
是否性别都為男:false
是否存在性别為男:true
所有元素性别不為男:false
2.3.2 findFirst、findAny()
findFirst() :擷取集合中的第一個元素資訊,例如:擷取集合第一個元素資訊的姓名。
findAny() :擷取流中的任意元素,具有不确定性。
//findFirst
String name = experts.stream().findFirst().orElseGet(Expert::new).getName();
System.out.println("擷取第一個元素的姓名:"+name);
//findAny
String anyName = experts.stream().findAny().orElseGet(Expert::new).getName();
System.out.println("擷取符合條件任意元素的姓名:"+anyName);
複制代碼
輸出:
擷取第一個元素的姓名:jiashn
擷取符合條件任意元素的姓名:jiashn
2.3.3 count
count() :統計流中元素個數,可以與filter進行使用來統計符合條件的元素個數。例如:統計年齡大于23歲的人員個數
//count
long count = experts.stream().filter(expert -> expert.getAge() > 23).count();
System.out.println("年齡大于23歲的人員個數:"+count);
複制代碼
輸出:
年齡大于23歲的人員個數:3
2.3.4 max、min
max(Comparator c) :傳回流中符合條件的最大值。例如:擷取集合年齡最大的元素資訊。
min(Comparator c) :傳回流中符合條件的最小值。例如:擷取集合年齡最小的元素資訊。
//max
Expert maxExpert = experts.stream().max(Comparator.comparing(Expert::getAge)).get();
System.out.println("年齡最大人員資訊:"+maxExpert);
//min
Expert minExpert = experts.stream().min(Comparator.comparing(Expert::getAge)).get();
System.out.println("年齡最小人員資訊:"+minExpert);
複制代碼
輸出:
年齡最大人員資訊:Expert(name=王五-wangwu, gender=女, age=26)
年齡最小人員資訊:Expert(name=jiashn, gender=男, age=20)
2.3.5 forEach
forEach(Consumer c) :内部循環,例如擷取所有元素的姓名
//forEach
StringJoiner sj = new StringJoiner(",");
experts.forEach(expert -> sj.add(expert.getName()));
System.out.println("所有人員姓名:"+sj.toString());
複制代碼
輸出:
所有人員姓名:jiashn,張三-zhangsan,王五-wangwu,李四-lisi,李四-lisi
當然也可以使用map,Collectors.joining(",") 實作上述功能,參見map的使用。
2.3.6 reduce
reduce(T iden, BinaryOperator b) :将流中元素反複結合起來,得到一個值,傳回T
reduce(BinaryOperator b) :将流中元素反複結合起來,得到一個值,傳回Optional。例如:擷取所有人員年齡的總和
//reduce
int totalAge = experts.stream().mapToInt(Expert::getAge).reduce(0, (total, age) -> {
total += age;
return total;
});
System.out.println("所有人員年齡總和:"+totalAge);
複制代碼
輸出:
所有人員年齡總和:115
2.3.7 collect(Collector c)
collect(Collector c) :将流轉換成其他形式。例如:list,set等。常用的方法:
toList:将流轉換成list集合輸出。上述例子中很多就用到
toSet:将流轉換成set集合輸出。例如:擷取姓名
joining:連接配接流中每個元素,傳回字元串,例如:運用map中的提到的擷取所有使用者姓名,使用","連接配接
groupingBy:分組,根據某些元素進行分組,例如:根據性别進行分組
partitioningBy:分區,根據true或false進行分區。例如:根據年齡大于23進行分區
summarizingDouble:彙總,統計元素的最大值,最小值等,例如:根據年齡進行彙總
當然stream還提供了其他的方法,如:counting,summingInt等。
//toSet
Set<String> nameSet = experts.stream().map(Expert::getName).collect(Collectors.toSet());
System.out.println("所有姓名:"+nameSet);
//groupingBy
Map<String, List<Expert>> genderMap = experts.stream().collect(Collectors.groupingBy(Expert::getGender));
System.out.println("性别分組資訊:"+genderMap);
//summarizingDouble
DoubleSummaryStatistics statistics = experts.stream().collect(Collectors.summarizingDouble(Expert::getAge));
System.out.println("年齡最大值:"+statistics.getMax());
System.out.println("年齡最小值:"+statistics.getMin());
System.out.println("年齡平均值:"+statistics.getAverage());
System.out.println("年齡總和值:"+statistics.getSum());
System.out.println("總人數:"+statistics.getCount());
//partitioningBy
Map<Boolean, List<Expert>> collect = experts.stream().collect(Collectors.partitioningBy(jia -> jia.getAge() > 23));
List<Expert> gtExpert= collect.get(Boolean.TRUE);
List<Expert> ltExpert= collect.get(Boolean.FALSE);
System.out.println("年齡大于23歲的資料:"+gtExpert);
System.out.println("年齡小于等于23歲的資料:"+ltExpert);
複制代碼
輸出:
所有姓名:[jiashn, 張三-zhangsan, 王五-wangwu, 李四-lisi]
性别分組資訊:{女=[Expert(name=張三-zhangsan, gender=女, age=21), Expert(name=王五-wangwu, gender=女, age=26)], 男=[Expert(name=jiashn, gender=男, age=20), Expert(name=李四-lisi, gender=男, age=24), Expert(name=李四-lisi, gender=男, age=24)]}
年齡最大值:26.0
年齡最小值:20.0
年齡平均值:23.0
年齡總和值:115.0
總人數:5
年齡大于23歲的資料:[Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24), Expert(name=李四-lisi, gender=男, age=24)]
年齡小于等于23歲的資料:[Expert(name=jiashn, gender=男, age=20), Expert(name=張三-zhangsan, gender=女, age=21)]
jdk1.8中的Stream的出現,讓我們對集合的操作變得簡單,業精于勤荒于嬉,我們多多使用,自然會對這些方法使用熟練掌握。