Java8 Stream 常用操作

Stream是Java8中的一大亮點,支持順序和並行聚合操作的一系列元素,爲了執行計算,流operations被組合成流管道 。 流管線由源(其可以是陣列,集合,生成函數,I / O通道等)組成,零個或多個中間操作 (其將流轉換成另一個流,例如filter(Predicate) )以及終端操作 (產生結果或副作用,如count()forEach(Consumer)

Stream和集合的不同點

  1. 沒有存儲。 流不是存儲元素的數據結構; 相反,它通過計算操作的流水線傳送諸如數據結構,陣列,生成器功能或I / O通道的源的元件。
  2. 功能性質。 流上的操作產生結果,但不會修改其來源。 例如,過濾從Stream獲得的Stream會生成新的Stream而不需要過濾的元素,而不是從源集合中刪除元素。
  3. 懶惰尋求。 許多流操作(如過濾,映射或重複刪除)可以懶惰地實現,從而暴露優化的機會。 例如,“找到具有三個連續元音的第一個String ”不需要檢查所有的輸入字符串。 流操作分爲中間( Stream生產)操作和終端(價值或副作用生成)操作。 中級操作總是懶惰。
  4. 可能無限。 雖然集合的大小有限,但流不需要。 諸如limit(n)或findFirst()之類的limit(n) findFirst()可以允許無限流上的計算在有限的時間內完成。
  5. 消耗品流的元素只能在流的一生中訪問一次。 像Iterator一樣 ,必須生成一個新流來重新訪問源的相同元素。

 Stream流的獲取

  1. Collection通過stream()parallelStream()方法;
  2. 從數組通過Arrays.stream(Object[]) ;
  3. 從流類靜態工廠的方法,如Stream.of(Object[])IntStream.range(int, int)Stream.iterate(Object, UnaryOperator) ;
  4. 文件的行可以從BufferedReader.lines()獲取 ;
  5. 文件路徑的流可以從Files中的方法獲得;
  6. 隨機數流可以從Random.ints()獲得;
  7. JDK中其它的數據流的方法,包括BitSet.stream()Pattern.splitAsStream(java.lang.CharSequence)JarFile.stream()
        //1.定義Collection
        List<String> list = new ArrayList<>();
        //獲取一個串行流
        Stream<String> stream = list.stream();
        //獲取一個並行流-底層是forkJoin實現
        Stream<String> stringStream = list.parallelStream();

        //2. 使用Arrays 中的 stream() 方法,將數組轉成流
        String[] array = new String[5];
        Stream<String> stream = Arrays.stream(array);

        //3.流類靜態工廠的方法

        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);//1 2 3 4 5 6

        Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2).limit(6);// 0 2 4 6 8 10

        Stream<Double> stream = Stream.generate(Math::random).limit(2);//隨機的2個數字


        //4.使用 BufferedReader.lines() 方法,從文件中將每行內容轉成流
        BufferedReader reader = new BufferedReader(new FileReader("D:\\milla_stream.txt"));
        Stream<String> lineStream = reader.lines();

        //5.文件路徑的流可以從Files中的方法獲得
        Stream<Path> stream = Files.list(Paths.get("D:\\"));

        //6.隨機數流可以從Random.ints()獲得;
        IntStream ints = new Random().ints();//是Stream的子類

        //7. 其他類中的方法
        IntStream stream1 = new BitSet().stream();//是Stream的子類

        Pattern pattern = Pattern.compile(",");
        Stream<String> text = pattern.splitAsStream("mila,love");

        Stream<JarEntry> stream2 = new JarFile("D:\\milla.jar").stream();

 流的中間操作

實體類

@Data
public class StudentVO {
    private String username;
    private String city;
    private String sex;
    private int age;
    public StudentVO(String username, String city, String sex, int age) {
        this.username = username;
        this.city = city;
        this.sex = sex;
        this.age = age;
    }
    public StudentVO() {
    }
}
@Data
public class TeacherVO {

    private String username;

    private String city;
}

 創建新的流

//生程流對象
   Stream<StudentVO> stream = Stream.of(
                new StudentVO("AA", "上海", "女", 22),
                new StudentVO("BB", "南京", "男", 20),
                new StudentVO("BB", "杭州", "女", 19),
                new StudentVO("CC", "杭州", "男", 20),
                new StudentVO("DD", "南京", "女", 22),
                new StudentVO("DD", "上海", "女", 23),
                new StudentVO("DD", "北京", "男", 22),
                new StudentVO("EE", "杭州", "男", 23),
                new StudentVO("FF", "上海", "女", 24));

 

映射-轉換

  • map: - 接收函數中的參數,根據業務將它變成一個新的元素
  • flatMap:- 接收函數中的參數,將每個值都進行業務替換,形成一個新的流
        //獲取所有學生的姓名-集合
        List<String> usernameList = list.stream().map(StudentVO::getUsername).collect(Collectors.toList());
        List<String> usernameList2 = list.stream().collect(Collectors.mapping(studentVO ->
             studentVO.getUsername(), Collectors.toList()));
        System.out.println("學生姓名集合:" + usernameList);
        System.out.println("學生姓名集合:" + usernameList2);


        //數據轉換
        List<TeacherVO> collect1 = list.stream().flatMap((e) -> {
            TeacherVO teacher = new TeacherVO();
            teacher.setUsername(e.getUsername());
            teacher.setCity(e.getCity());
            return Stream.of(teacher);
        }).collect(Collectors.toList());
        System.out.println(collect1);


排序

  • sorted()  - 返回由此流的元素組成的流,根據自然順序排序
  • sorted(Comparator<? super T> comparator) -  返回由該流的元素組成的流,根據提供的 Comparator進行排序。
 //按照年齡和姓名排序-正序
        List<StudentVO> sortedList = list.stream().sorted(
            Comparator.comparingInt(StudentVO::getAge)
            .thenComparing(StudentVO::getUsername)
            .reversed()).collect(Collectors.toList());
        System.out.println("按照年齡排序:" + sortedList);

篩選 - 截取

  • filter(Predicate<? super T> predicate); - 過濾,指定過濾條件
  • limit(n) - 獲取n個元素
  • skip(n) - 丟棄流的第一個 n元素後,返回由該流的 n元素組成的流,和 limit(n) 協作可實現分頁
  • distinct - 去除重複數據(根據equals() 和 hashCode()方法)
//地址在杭州的學生數量
Stream<StudentVO> voStream = list.stream().filter(stu -> stu.getCity().equals("杭州")).distinct().limit(5).skip(2);

 消費

  • peek(Consumer<? super T> action)  - 得到每個元素並對其進行操作,與map的區別不需要返回操作的元素,與forEch的區別是該方法返回流對象能繼續流式操作
//中間操作不執行,只有終端操作的時候纔會執行打印
        list.stream().peek(stu -> {
            System.out.println("學生對象:  " + stu);
        }).count();

 流的終止操作

        allMatch  -   接收一個 Predicate 函數,當流中每個元素都符合該斷言時才返回true,否則返回false
        noneMatch  -   接收一個 Predicate 函數,當流中每個元素都不符合該斷言時才返回true,否則返回false
        anyMatch  -   接收一個 Predicate 函數,只要流中有一個元素滿足該斷言則返回true,否則返回false
        findFirst  -   返回流中第一個元素
        findAny  -   返回流中的任意元素
        count  -   返回流中元素的總個數
        max  -   返回流中元素最大值
        min  -   返回流中元素最小值

JDK中給出的Collectors的常用操作

    //獲取用戶的名稱組成中集合
   List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

   //將名稱變成set返回-有序
   Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));

   //使用逗號連接符連接
   String joined = things.stream()
                         .map(Object::toString)
                         .collect(Collectors.joining(", "));

   //計算元算的工資總和
   int total = employees.stream()
                        .collect(Collectors.summingInt(Employee::getSalary)));

   //根據部門分組
   Map<Department, List<Employee>> byDept
       = employees.stream()
                  .collect(Collectors.groupingBy(Employee::getDepartment));

   //根據部門分組並計算各個部分的工資總和
   Map<Department, Integer> totalByDept
       = employees.stream()
                  .collect(Collectors.groupingBy(Employee::getDepartment,
                                                 Collectors.summingInt(Employee::getSalary)));

   //根據條件-滿足條件的分組
   Map<Boolean, List<Student>> passingFailing =
       students.stream()
               .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));

 

 常用獲取對象集合操作

       Stream<StudentVO> stream = Stream.of(
                new StudentVO("AA", "上海", "女", 22),
                new StudentVO("BB", "南京", "男", 20),
                new StudentVO("BB", "杭州", "女", 19),
                new StudentVO("CC", "杭州", "男", 20),
                new StudentVO("DD", "南京", "女", 22),
                new StudentVO("DD", "上海", "女", 23),
                new StudentVO("DD", "北京", "男", 22),
                new StudentVO("EE", "杭州", "男", 23),
                new StudentVO("FF", "上海", "女", 24));
        //將學生對象變成集合
        List<StudentVO> list = stream.collect(Collectors.toList());
        System.out.println("學生集合: " + list);
        //獲取所有學生的姓名-集合
        List<String> usernameList = list.stream().map(StudentVO::getUsername).collect(Collectors.toList());
        List<String> usernameList2 = list.stream().collect(Collectors.mapping(studentVO -> studentVO.getUsername(), Collectors.toList()));
        System.out.println("學生姓名集合:" + usernameList);
        System.out.println("學生姓名集合:" + usernameList2);
        //合併學生的姓名-連接程字符串
        String usernameJoin = list.stream().map(StudentVO::getUsername).collect(Collectors.joining("-"));
        System.out.println("學生姓名連接: " + usernameJoin);
        //地址在杭州的學生數量
        Stream<StudentVO> voStream = list.stream().filter(stu -> stu.getCity().equals("杭州")).distinct().limit(5).skip(2);


        long countHz = list.stream().filter(stu -> stu.getCity().equals("杭州")).count();
        System.out.println("杭州學生的個數:" + countHz);
        //按照所在城市分組
        Map<String, List<StudentVO>> groupByList = list.stream().collect(Collectors.groupingBy(studentVO -> studentVO.getCity()));
        System.out.println("按照城市分組:" + groupByList);
        //按照年齡和姓名排序-正序
        List<StudentVO> sortedList = list.stream().sorted(Comparator.comparingInt(StudentVO::getAge).thenComparing(StudentVO::getUsername).reversed()).collect(Collectors.toList());
        System.out.println("按照年齡排序:" + sortedList);
        //學生姓名作爲key轉變成map->如果有有重複的key,需要做個取捨-否則會報錯
        Map<String, StudentVO> usernameKey = list.stream().collect(Collectors.toMap(studentVO -> studentVO.getUsername(), studentVO -> studentVO, (one, two) -> {
            //可以根據業務保留第一個元素或者是第二個元素
            return one;
        }));
        Map<String, String> usernameKey2 = list.stream().collect(Collectors.mapping(stu -> stu.getUsername(), Collectors.toMap(stu -> stu, stu -> stu, (one, two) -> one)));
        System.out.println("將學生姓名作爲key: " + usernameKey);
        System.out.println("將學生姓名作爲key: " + usernameKey2);
        //根據城市分組,然後再按照學生名變成map-所有變成map的操作都需要考慮重複元素的問題
        Map<String, Map<String, StudentVO>> collect = list.stream().collect(Collectors.groupingBy(stu -> stu.getCity(), Collectors.toMap(stu -> stu.getUsername(), studentVO -> studentVO)));
        System.out.println(collect);

        //數據轉換
        List<TeacherVO> collect1 = list.stream().flatMap((e) -> {
            TeacherVO teacher = new TeacherVO();
            teacher.setUsername(e.getUsername());
            teacher.setCity(e.getCity());
            return Stream.of(teacher);
        }).collect(Collectors.toList());
        System.out.println(collect1);

        StudentVO studentVO = list.parallelStream().findAny().get();
        System.out.println(studentVO);


        //中間操作不執行,只有終端操作的時候纔會執行打印
        list.stream().peek(stu -> {
            System.out.println("學生對象:  " + stu);
        }).count();

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章