Java8 Stream API使用示例
Stream是什麼?
Java8中的Stream,也叫流,不過不同于IO流,它是對集合操作的一個增強API,個人了解,1、它使用内部疊代操作集合;2、它提供了類似資料庫中count、avg等聚合操作,學習過程中留個記錄,話不多說,上代碼。
import java.util.ArrayList;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
/**
* 建立流
* 1、Collection等通過stream()方法、Arrays中得靜态方法stream()擷取數組流
* 2、Stream.of(),Stream.iterate()、Stream.generate()無限流
*/
//初始化資料
List<Student> list = new ArrayList<>();
list.add(new Student(5, "張三", 22,"國文", 85));
list.add(new Student(1, "李四", 23,"數學", 86));
list.add(new Student(4, "麻子", 21,"國文", 82));
list.add(new Student(6, "麻子", 21,"英語", 98));
list.add(new Student(2, "張三", 22,"數學", 99));
list.add(new Student(7, "李四", 23,"國文", 90));
//list.add(new Student(8, "李四", 23,"國文", 90)); //測試去重的時候可以加上這條記錄
/*
* 1.1、filter 過濾資料,留下入參傳回true的資料
* 需求:查詢分數大于90的人
*/
List<Student> collect = list.stream().filter(s -> s.getScore()>90).collect(Collectors.toList());
System.out.println("1.1、filter 查詢分數大于90的人:"+collect);
/*
* 1.2、filter 過濾資料,留下入參傳回true的資料
* 需求:查詢國文分數大于等于90的人
*/
List<Student> c2 = list.stream()
.filter(s -> {
if(s.getSubject().equals("國文") && s.getScore()>=90){
return true;
}else{
return false;
}
}).collect(Collectors.toList());
System.out.println("1.2、filter 查詢國文分數大于等于90的人:"+c2);
/*
*這裡輸出用了lambda的方法引用
*概念:對于一個lambda表達式隻是調用了一個方法時,可以用方法引用的方式簡化lambda表達式
*方法引用的标準形式是:類名::方法名。(注意:隻需要寫方法名,不需要寫括号)
有以下四種形式的方法引用:
類型 示例
引用靜态方法 ContainingClass::staticMethodName
引用某個對象的執行個體方法 containingObject::instanceMethodName
引用某個類型的任意對象的執行個體方法 ContainingType::methodName
引用構造方法 ClassName::new
*
*/
list.stream()
.filter(s -> {
if(s.getSubject().equals("國文") && s.getScore()>=90){
return true;
}else{
return false;
}
}).forEach(System.out::println); //方法引用
/*
* 2.1、map 轉換,可以将原對象轉換成另一個對象流
* 典型需求:得到id清單
*/
List<Integer> idList = list.stream().map(Student::getId).collect(Collectors.toList());
System.out.println("2.1、map 由List<Student>轉換後得到List<Integer>id清單:"+idList);
/*
* 2.2、mapToDouble 轉換,可以将原對象流轉換成Double流
* 典型需求:求張三的平均分
*/
OptionalDouble average = list.stream()
.filter(s -> s.getName().equals("張三")) //保留張三的記錄
.mapToDouble(Student::getScore) //将分數轉成一個mapToDouble流
.average(); //求平均分
DoubleSummaryStatistics summary = list.stream()
.filter(s -> s.getName().equals("張三")) //保留張三的記錄
.mapToDouble(Student::getScore) //将分數轉成一個mapToDouble流
.summaryStatistics();
System.out.println("2、mapToDouble 求張三的平均分:" + (average.isPresent()?average.getAsDouble():average.orElse(0)));
System.out.println("2、summaryStatistics 張三分數統計:" + "總分:"+summary.getSum()+",最高分:"+summary.getMax()+",最低分:"+summary.getMin()+",共幾科:"+summary.getCount()+",平均分:"+summary.getAverage());
/*
* 3、distinct 去重,根據對象的hashCode和equals方法去重
* 典型需求:清單去重
*/
List<Student> distinctList = list.stream().distinct().collect(Collectors.toList());
System.out.println("3、distinct 去重後清單:"+distinctList);
/*
* 4、sort 排序,可以自定義排序規則
* 需求:先根據姓名升序,再根據科目升序,在再根據分數降序
*/
List<Student> sortedList = list.stream().sorted(Comparator.comparing(Student::getName) //姓名升序
//.thenComparing(Student::getSubject) //科目升序
.thenComparing(Student::getScore).reversed()) //分數降序
.collect(Collectors.toList());
System.out.println("4、sort 先根據姓名升序,再根據科目升序,在再根據分數降序:"+sortedList);
/*
* 5、peek 什麼都不幹,一般用于調試,輸出元素啥的
* 按照Java團隊的說法,peek()方法存在的主要目的是用調試,通過peek()方法可以看到流中的資料經過每個處理點時的狀态
* 需求:過濾長度大于3的字元串,轉成大寫
*/
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3) //長度大于3的,得到 "three", "four"
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase) // 轉成大寫
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
/*
* 6、limit 截取前N條資料
* 需求:截取前3條資料
*/
List<Student> limitList = list.stream().limit(3)
.collect(Collectors.toList());
System.out.println("6、limit 截取前3條資料:"+limitList);
/*
* 6、skip 跳過N條資料
* 需求:跳過1條資料
*/
List<Student> skipList = list.stream().skip(1)
.collect(Collectors.toList());
System.out.println("7、skip 跳過1條資料:"+skipList);
/*
* 7.1、reduce 歸約(把值合成一個) 使用隻有一個入參的情況
* Optional<T> reduce(BinaryOperator<T> accumulator);
* 需求:求和
*/
Optional<Integer> accResult = Stream.of(1, 2, 3, 4)
.reduce((acc, item) -> { //第一個參數是統計值,第一次執行是第一個元素;第二個參數是流元素,第一次是第二個元素
System.out.println("acc : " + acc); //統計結果,第一次執行是第一個元素
acc += item;
System.out.println("item: " + item); //流裡面的元素,第一次是第二個元素
System.out.println("acc+ : " + acc); //統計結果
System.out.println("--------");
return acc;
});
System.out.println("7.1、reduce 歸約 使用隻有一個入參的情況 統計結果: " + accResult.get());
System.out.println("--------");
/*
* 7.2、reduce 歸約(把值合成一個) 使用有兩個入參的情況,第一個入參是統計初始值,第二個是累加器
* T reduce(T identity, BinaryOperator<T> accumulator);
* param :identity 是傳回結果
* param:accumulator 累加器
* 需求:求和
*/
Integer accResult2 = Stream.of(1, 2, 3, 4)
.reduce(0,(acc, item) -> { //第一個參數0是統計結果初始值;第二個參數是累加器,跟上面一樣
System.out.println("acc2 : " + acc); //統計結果,第一次執行是初始值0
acc += item;
System.out.println("item2: " + item); //流裡面的元素,第一次是第1個元素
System.out.println("acc2+ : " + acc); //統計結果
System.out.println("--------");
return acc;
});
System.out.println("7.2、reduce 歸約 使用有兩個入參的情況 統計結果2: " + accResult2);
System.out.println("--------");
/*
* 8.1、Collectors.groupingBy
* 需求:根據姓名分組
* return Map<String, List<Student>>, key姓名,value:該姓名對應的對象清單
*/
Map<String, List<Student>> groupList = list.stream()
.collect(Collectors.groupingBy(Student::getName));
System.out.println("8.1、Collectors.groupingBy 根據姓名分組:"+groupList);
/*
* 8.2、Collectors.groupingBy
* 需求:根據姓名分組,并統計每個分組有多少個元素(count)
* return Map<String, Long>, key:姓名,value:該組有多少個元素
* 例:{李四=2, 張三=2, 麻子=2}
*/
Map<String, Long> groupCount = list.stream()
.collect(Collectors.groupingBy(Student::getName,Collectors.counting()));
System.out.println("8.2、Collectors.groupingBy 根據姓名分組,并統計每個分組有多少個(count):"+groupCount);
/*
* 8.3、Collectors.groupingBy
* 需求:根據姓名分組,并統計每個分組各科平均分
* return Map<String, Double>, key:姓名,value:平均分
* 例:{李四=88.0, 張三=92.0, 麻子=90.0}
*/
Map<String, Double> groupAvg = list.stream()
.collect(Collectors.groupingBy(Student::getName,Collectors.averagingDouble(Student::getScore)));
System.out.println("8.3、Collectors.groupingBy 根據姓名分組,并統計每個分組各科平均分:"+groupAvg);
/*
* 8.4、Collectors.groupingBy
* 需求:根據姓名分組,并統計每個分組總分
* return Map<String, Double>, key:姓名,value:總分
* 例:{李四=176.0, 張三=184.0, 麻子=180.0}
*/
Map<String, Double> groupSum = list.stream()
.collect(Collectors.groupingBy(Student::getName,Collectors.summingDouble(Student::getScore)));
System.out.println("8.4、Collectors.groupingBy 根據姓名分組,并統計每個分組總分:"+groupSum);
/*
* 8.5、Collectors.groupingBy 多字段分組
* 需求:根據姓名,學科分組
* return Map<String, Map<String, List<Student>>>, key:姓名,value:map(key:學科,value:清單)
* 例:{李四={數學=[Student [name=李四, subject=數學, score=86.0]], 國文=[Student [name=李四, subject=國文, score=90.0]]}, 張三={數學=[Student [name=張三, subject=數學, score=99.0]], 國文=[Student [name=張三, subject=國文, score=85.0]]}, 麻子={國文=[Student [name=麻子, subject=國文, score=82.0]], 英語=[Student [name=麻子, subject=英語, score=98.0]]}}
*/
Map<String, Map<String, List<Student>>> groups = list.stream()
.collect(Collectors.groupingBy(Student::getName,Collectors.groupingBy(Student::getSubject)));
System.out.println("8.5、Collectors.groupingBy 多字段分組-根據姓名,學科分組:"+groups);
}
private static class Student{
private int id; //id
private String name; //姓名
private int age; //年齡
private String subject; //學科
private float score; //分數
public Student(int id,String name,int age,String subject,float score){
this.id=id;
this.name=name;
this.age=age;
this.subject=subject;
this.score=score;
}
public int getId() {
return id;
}
@SuppressWarnings("unused")
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
@SuppressWarnings("unused")
public void setName(String name) {
this.name = name;
}
@SuppressWarnings("unused")
public int getAge() {
return age;
}
@SuppressWarnings("unused")
public void setAge(int age) {
this.age = age;
}
public float getScore() {
return score;
}
@SuppressWarnings("unused")
public void setScore(float score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", subject=" + subject + ", score=" + score + "]";
}
public String getSubject() {
return subject;
}
@SuppressWarnings("unused")
public void setSubject(String subject) {
this.subject = subject;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (subject == null) {
if (other.subject != null)
return false;
} else if (!subject.equals(other.subject))
return false;
return true;
}
}
}