總算給女盆友講明白了,如何使用stream流的filter()操作

2022-12-02 06:00:47

一、引言

在上一篇文章中《這麼簡單,還不會使用java8 stream流的map()方法嗎?》分享了使用stream的map()方法,不知道小夥伴還有印象嗎,先來回顧下要點,map()方法是把一個流中的元素T轉換為另外一個新流中的元素R,轉換完成後兩個流的元素個數不發生改變,具體怎麼使用,請小夥伴移步上篇檢視。在上篇文章中遺留了一個問題,本篇文章來解決它。先來看stream的另一個API--filter()方法。

二、概述

先來看下filter方法的定義,

該方法返回一個新流,這個新流中的元素要匹配給定的表示式。從方法的入參及出參可以看到返回的新流中的元素和元素流中的元素型別是一致的,和map()方法不同的是新流的元素個數要小於等於原始流的元素個數。

下面看下示意圖,更清晰,

是不是很簡單,下面看下具體的用法。

三、詳述

以」找出一年級的所有學生的成績「為例,來看下怎麼使用filter()方法。同樣初始化五個學生,

Data.java

package com.example.log.stream.test;

import com.example.log.stream.entity.Student;
import java.util.ArrayList;
import java.util.List;

/**
 * @date 2022/11/30 22:43
 */
public class Data {
    public static List<Student> initData(){
        List<Student> students= new ArrayList<>();

        Student s1=new Student();
        s1.setName("王五");
        s1.setSchoolClass("一年級");
        s1.setChineseScore(100);
        s1.setMathScore(100);
        students.add(s1);

        Student s2=new Student();
        s2.setName("李四");
        s2.setSchoolClass("一年級");
        s2.setChineseScore(100);
        s2.setMathScore(100);
        students.add(s2);

        Student s3=new Student();
        s3.setName("李思");
        s3.setSchoolClass("二年級");
        s3.setChineseScore(100);
        s3.setMathScore(100);
        students.add(s3);

        Student s4=new Student();
        s4.setName("王五");
        s4.setSchoolClass("三年級");
        s4.setChineseScore(100);
        s4.setMathScore(100);
        students.add(s4);

        Student s5=new Student();
        s5.setName("趙三");
        s5.setSchoolClass("一年級");
        s5.setChineseScore(100);
        s5.setMathScore(100);
        students.add(s5);
        return students;
    }
}

Student.java類這裡不在貼出,有興趣的可以自己寫,或參考上篇文章中的定義。直接看怎麼實現。

3.1、找出一年級的所有學生成績

要找出一年級的所有學生成績,就要根據schoolClass進行過濾,看下使用filter()方法怎麼寫。

package com.example.log.stream.test;

import com.example.log.stream.entity.Student;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 測試filter()方法
 * @date 2022/12/1 21:01
 */
public class TestFilter {
    public static void main(String[] args) {
        List<Student> students=Data.initData();
        //使用filter對schoolClass進行過濾,滿足條件的返回true,否則返回false,達到過濾的目的
        List<Student> firstClass=students.stream().filter(student -> {
            if("一年級".equals(student.getSchoolClass())){
                return true;
            }
            return false;
        }).collect(Collectors.toList());
        //列印新的流
        for (Student student:firstClass) {
            System.out.println(student);
        }
        System.out.println("---------------------");
        for (Student student:students) {
            System.out.println(student);
        }
    }
}

使用filter()方法,該方法中的函數式介面,返回一個boolean型別的值,從而決定了該元素是否會寫入到新流中。看下結果,

如果現在有這樣一個需求,找出所有的一年級的學生,並給他們的數學成績都減1分。要怎麼辦?

3.2、給一年級的所有同學的數學成績減1分

我們可以在上面的基礎上進行修改,完成此需求,

package com.example.log.stream.test;

import com.example.log.stream.entity.Student;
import java.util.List;
import java.util.stream.Collectors;
/**
 * 測試filter()方法
 * @date 2022/12/1 21:01
 */
public class TestFilter {
    public static void main(String[] args) {
        List<Student> students=Data.initData();
        //使用filter對schoolClass進行過濾,滿足條件的返回true,否則返回false,達到過濾的目的
        List<Student> firstClass=students.stream().filter(student -> {
            if("一年級".equals(student.getSchoolClass())){
                //所有一年級的學生,數學減1分
                student.setMathScore(student.getMathScore()-1);
                return true;
            }
            return false;
        }).collect(Collectors.toList());
        //列印新的流
        for (Student student:firstClass) {
            System.out.println(student);
        }
        System.out.println("---------------------");
        for (Student student:students) {
            System.out.println(student);
        }
    }
}

只需在上面的基礎上增加一行程式碼即可,即符合條件的都減1分,看下列印結果。

從上面的解僱可以看到使用filter完成了該功能,但帶來的一個副作用是原始資料也變了,主要是因為修改的是通過一個參照指向的物件。其實不太建議這樣去寫,因為filter()方法從字面意思就可以知道,它的作用就是過濾,最好不要參雜其他的邏輯,可以再加一個map()方法。

TestFilter2.java

package com.example.log.stream.test;

import com.example.log.stream.entity.Student;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 測試filter()方法
 * @date 2022/12/1 21:01
 */
public class TestFilter2 {
    public static void main(String[] args) {
        List<Student> students=Data.initData();
        //使用filter對schoolClass進行過濾,滿足條件的返回true,否則返回false,達到過濾的目的
        List<Student> firstClass=students.stream().filter(student -> {
            if("一年級".equals(student.getSchoolClass())){
                return true;
            }
            return false;
        }).map(student -> {//map()方法
            //設定數學成績減1
            student.setMathScore(student.getMathScore()-1);
            return student;
        }).collect(Collectors.toList());
        //列印新的流
        for (Student student:firstClass) {
            System.out.println(student);
        }
        System.out.println("---------------------");
        for (Student student:students) {
            System.out.println(student);
        }
    }
}

上面在使用完filter後,由於是一個stream流,那麼繼續使用map()方法,對上一步過濾出的元素再對數學成績減1操作,最後得到結果。通過一個示意圖,

這樣是不是比直接在fliter()中更加清晰。

四、總結

stream的filter()方法是要通過true/false來篩選元素,為true的會放到新流中,反之為false的不會放到新流中。

推薦閱讀

這麼簡單,還不會使用java8 stream流的map()方法嗎?

有不正之處,歡迎指正,謝謝!

感謝動動小手關注公眾號【良工說技術】,更多精彩不容錯過。