目錄
前言
其實最近自己看了不少的關於list流的操作文章,但是總覺得自己好像差點意思,只有有一天,自己好像忽然就明白了stream操作流的使用方式,不得不說,這個操作真的是行雲流水以及上手,現在感覺就是開心,非常開心
正文
1.準備數據
1.1 實體類
我們先來準備一個實體類,用來模擬我們正常業務開發中的實體類,也可以當做是map,下面的內容,我會一點一點來說明目前我所理解的流操作。
實體類代碼:
public class Student {
private int number;
private String name;
private String clazz;
private int score;
public Student(int number, String name, String clazz, int score) {
this.number = number;
this.name = name;
this.clazz = clazz;
this.score = score;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"number=" + number +
", name='" + name + '\'' +
", clazz='" + clazz + '\'' +
", score=" + score +
'}';
}
}
1.2 操作測試類
準備數據的代碼
private static final List<Student> STUDENTS = create();
private static final String CLAZZ1 = "軟件1班";
private static final String CLAZZ2 = "軟件2班";
private static List<Student> create() {
Student s1 = new Student(2018008, "張揚", CLAZZ2, 66);
Student s2 = new Student(2018005, "劉飛", CLAZZ1, 92);
Student s3 = new Student(2018007, "李明", CLAZZ2, 42);
Student s4 = new Student(2018006, "趙勇", CLAZZ2, 56);
Student s5 = new Student(2018002, "王磊", CLAZZ1, 81);
Student s6 = new Student(2018010, "牛娜", CLAZZ1, 78);
List<Student> students = new ArrayList<>();
students.add(s1);students.add(s2);students.add(s3);
students.add(s4);students.add(s5);students.add(s6);
return students;
}
接下來我們要上作業了,在下面寫上我們的main方法,把需求寫在上面然後慢慢來。好了,來看一下這次我們的任務是哪些?
public static void main(String[] args) {
//方法1,獲取成績小於等於指定分數的全部學生
//方法2,獲取指定班級,成績小於等於指定分數,的全部學生
//方法3,獲取指定班級,成績小於等於指定分數,的全部學生的姓名。注意返回類型
//方法4,按成績由低到高排序,返回全部學生
//方法5,獲取指定班級,成績小於等於指定分數,成績由高到低排序,的全部學生
//方法6,獲取指定班級,成績小於等於指定分數,成績由高到低排序,的全部學生的學號。注意返回類型
//方法7,獲取指定班級,成績小於等於指定分數,的全部學生
}
2.實現數據篩選
2.1 獲取成績小於等於指定分數的全部學生
先明確我們目的,要獲取成績小於等於指定分數,我們先假定這個分數爲75,那麼我們要使用流來進行操作,所以第一步,我們要先拿到這個list的流,那麼先寫出我們的代碼,
STUDENTS.stream()
這樣我們就拿到我們的流了,然後看需要,我們要拿到成績小於等於指定分數,也就是說我們是要在這些數據中做篩選了,那麼我點在上面的代碼添加.之後,會出現很多的方法,如下圖
有些方法我們先不講,我們這次是要做篩選,所以我們選擇filter,那麼我們的代碼就變成了這樣
STUDENTS.stream().filter()
選擇了filter之後,我們要在filter裏面寫上我們的篩選條件,通常我們都是使用lambda表達式,我們的list中每一個對應都是一個Student,所以我們先用一個變量來標識這個student,這個變量,和你正常遍歷的使用for遍歷的i是一個功能,然後加入我們的篩選條件,成績小於等於75,然後我們的代碼就變成了
STUDENTS.stream().filter(student -> student.getScore() <= 75)
這樣我們的過濾就已經做完了,現在我們要拿到他返回的結果,我們在代碼後面繼續點,讓這個結果變成一個集合,所以我們需要把這個結果收集起來,所以我們選擇collect,這樣代碼就變成了
STUDENTS.stream().filter(student -> student.getScore() < 75).collect()
那麼我們以什麼樣的結果返回那,通常我們也是希望它能爲我們返回一個list,那麼我們在collect裏面告訴他,幫我返回list,我們藉助集合工具類,代碼就變成了
STUDENTS.stream().filter(student -> student.getScore() < 75).collect(Collectors.toList());
任務完成,加上分號,存儲變量打印輸出!看結果
下一個!!!
2.2 獲取指定班級,成績小於等於指定分數,的全部學生
這個需求,和上面什麼區別,我xxxxx,好吧,現在我們假定獲取軟件2班的同學吧(爲了偷懶就不讓他們選擇了,這個參數是可以傳遞的),那我們的代碼需要變得是哪裏,沒錯,就是我們的過濾條件,那我們怎麼改那,我直接雙&行不行,搞一下不就曉得了。來,上代碼
List<Student> collect2 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() <= 75).collect(Collectors.toList());
任務完成,加上分號,存儲變量打印輸出!看結果
怎麼又是你們!看了一眼數據,沒錯啊,就是你們,小於75的都是二班的!!!!
下一個!!!!
2.3 獲取指定班級,成績小於等於指定分數,的全部學生的姓名。注意返回類型
這個看樣子來新的需求了,不慌,看我搞定!
首先我們還是按照之前的數據來做過濾,那麼我們的代碼先寫成這個樣子
STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() <= 75)
這個時候我們已經做了過濾等級和班級,看他後面的需要,全部學生的姓名,那我們應該怎麼蒐集他的姓名呢,首先明確我們的目標,我們是要做收集對象的某一個屬性,filter肯定不對,foreach遍歷操作有點像,但是也不對,因爲foreach的操作時沒有返回值的(這個你試一下就知道了),那麼其他的方法名我們怎麼看都不太像,那就試一下map吧,裏面同樣寫出lambda表達式,我們獲取他的名稱,上代碼
List<String> collect3 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).map(student -> student.getName()).collect(Collectors.toList());
收集就一起寫上去了,看一下返回結果,好像是一個List 好像有戲,執行一下試一下
下一個!!!!
2.4 按成績由低到高排序,返回全部學生
這個簡單,我直接Arrays.sort(list.toArray)
等等,
我在說什麼,先看看我們的流又沒有提供排序功能吧,獲取流之後點一下,發現有一個sorted,嗯,像,那就試一下吧
所以我們代碼就變成了這樣
有兩個方法,一個需要傳遞比較器,一個不需要傳遞,看樣子不傳遞的應該就是默認的排序規則了吧,java默認的排序規則一般都是從小到大(實際上我也試了,是從小到大),student裏面沒有比較的方法,所以我們還是自己寫一個比較器吧,然後我們的代碼就變成了
List<Student> collect4 = STUDENTS.stream().sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore();
}
}).collect(Collectors.toList());
//打印輸出內容
collect4.stream().forEach(student -> System.out.println(student));
看執行結果
下一個!!!!!!
2.5 獲取指定班級,成績小於等於指定分數,成績由高到低排序,的全部學生
這個就是2.2和2.4組合,代碼應該不難理解,先排序還是先過濾都可以,建議還是先過濾 。注意排序規則變了,所以我們要修改我們的比較器。上代碼了
List<Student> collect5 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).collect(Collectors.toList());
執行結果
下一個!!!!
2.6 獲取指定班級,成績小於等於指定分數,成績由高到低排序,的全部學生的學號。注意返回類型
這,這個2.4有什麼區別,就是多了一個比較嗎?過,下一個
List<Integer> collect6 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).map(student -> student.getNumber()).collect(Collectors.toList());
2.7 獲取指定班級,成績小於等於指定分數,的全部學生
這個,怎麼感覺需求跟上面比還變簡單了呢,上代碼了
STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).collect(Collectors.toList());
附上完整版本代碼
public class StreamTest1 {
private static final List<Student> STUDENTS = create();
private static final String CLAZZ1 = "軟件1班";
private static final String CLAZZ2 = "軟件2班";
private static List<Student> create() {
Student s1 = new Student(2018008, "張揚", CLAZZ2, 66);
Student s2 = new Student(2018005, "劉飛", CLAZZ1, 92);
Student s3 = new Student(2018007, "李明", CLAZZ2, 42);
Student s4 = new Student(2018006, "趙勇", CLAZZ2, 56);
Student s5 = new Student(2018002, "王磊", CLAZZ1, 81);
Student s6 = new Student(2018010, "牛娜", CLAZZ1, 78);
List<Student> students = new ArrayList<>();
students.add(s1);students.add(s2);students.add(s3);
students.add(s4);students.add(s5);students.add(s6);
return students;
}
public static void main(String[] args) {
//方法1,獲取成績小於等於指定分數,的全部學生
System.out.println("-------------------------------");
List<Student> scoredayu = STUDENTS.stream().filter(student -> student.getScore() <= 75).collect(Collectors.toList());
scoredayu.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法2,獲取指定班級,成績小於等於指定分數,的全部學生
List<Student> collect2 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() <= 75).collect(Collectors.toList());
collect2.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法3,獲取指定班級,成績小於等於指定分數,的全部學生的姓名。注意返回類型
List<String> collect3 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).map(student -> student.getName()).collect(Collectors.toList());
collect3.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法4,按成績由低到高排序,返回全部學生
List<Student> collect4 = STUDENTS.stream().sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getScore()-o2.getScore();
}
}).collect(Collectors.toList());
collect4.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法5,獲取指定班級,成績小於等於指定分數,成績由高到低排序,的全部學生
List<Student> collect5 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).collect(Collectors.toList());
collect5.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
// //方法6,獲取指定班級,成績小於等於指定分數,成績由高到低排序,的全部學生的學號。注意返回類型
List<Integer> collect6 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getScore() - o1.getScore();
}
}).map(student -> student.getNumber()).collect(Collectors.toList());
collect6.stream().forEach(System.out::println);
System.out.println("-------------------------------");
// //方法7,獲取指定班級,成績小於等於指定分數,的全部學生
List<Student> collect7 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).collect(Collectors.toList());
collect7.stream().forEach(student -> System.out.println(student));
System.out.println("-------------------------------");
}
}
3 代碼優化
改動1
寫完了功能發現我的代碼在幹嘛,它再飄黃,有代碼潔癖的人看了肯定忍不了,來,看看怎麼優化,
看這個提示,什麼lambda可以被方法給替代,按照idea給的建議方案來改動
我們的打印代碼就變成了
collect7.forEach(System.out::println);
改動2
估計大家也能看到了飄黃的不止是這個地方,還有這個
雖然我英語不太好,但是憑藉着我的經驗我還是認出來了它的意思,
它的意思是比較器可以被lambda表達式給替代,那要是替代的話怎麼寫呢?直接alt+inter 看看idea給出的解決方案
List<Student> collect5 = STUDENTS.stream().filter(student -> CLAZZ2.equals(student.getClazz()) && student.getScore() < 75).sorted((o1, o2) -> o2.getScore() - o1.getScore()).collect(Collectors.toList());
看到了 其實就是將
換成了
這個改動之後,我總算是明白了爲什麼我之前看別人的例子,別人的例子總是那麼的簡潔,讓我有點些許的迷茫,不過現在知道這個結果怎麼來的之後,發現自己能看明白了這個操作。
4 Stream流API
Stream流的中間操作api有
api | 操作解釋 |
---|---|
limit | 指定幾條數據 |
skip | 跳過幾條數據從指定數據下標開始 |
distinct | 去重 |
map | 接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。 |
sorted | 排序 |
allMatch | 檢查是否匹配所有元素 |
anyMatch | 檢查是否至少匹配一個元素 |
noneMatch | 檢查是否沒有匹配所有元素 |
findFirst | 返回第一個元素 |
findAny | 返回當前流中的任意元素 |
count | 返回流中元素的總個數 |
max | 返回流中最大值 |
min | 返回流中最小值 |
關於其他的具體操作,我這裏就不在舉例子,如果業務中有需要要使用的話,建議大家先寫demo,還有,使用stream操作的時候,爲了防止後續人員看你的代碼懵逼,所以一定要在流上面寫註釋!!!,一定要在流上面寫註釋!!!一定要在流上面寫註釋!!!告訴別人你的這個操作目的是什麼!!!要不我就~~~~~~