主頁 > 後端開發 > 函式編程:強大的 Stream API

函式編程:強大的 Stream API

2023-03-07 07:09:36 後端開發

函式編程:強大的 Stream API

在這里插入圖片描述

每博一文案

只要有人的地方,世界就不會是冰冷的,我們可以平凡,但絕對不可以平庸,
                                          —————— 《平凡的世界》
                                          
人活著,就得隨時準備經受磨難,他已經看過一些書,知道不論是普通人還是了不起的人,
都要在自己的一生中經歷許多磨難,磨難使人堅強,
                                          —————— 《平凡的世界》
                                          
hellip... 人哪,活著是這么的苦,一旦你從幸福的彼岸被拋到苦難的此岸,你真
是處處走投無路,而現在你才知道,在天堂與地獄之間原來也只有一步之遙,
                                          ——————《平凡的世界》

@

目錄
  • 函式編程:強大的 Stream API
  • 每博一文案
  • 1. Stream 的概述
    • 1.1 為什么要使用Stream API
    • 1.2 什么是 Stream
    • 1.3 Stream 的操作三個步驟
    • 1.4 Stream 與 Colliection 的區別
  • 2. 創建 Stream 的四種方式
    • 2.1 創建Stream 方式一:通過集合
    • 2.2 創建 Stream 方式二:通過陣列
    • 2.3 創建 Stream 的方式三: 通過 Stream 的 of()
    • 2.4 創建 Stream 方式四: 創建無限流
  • 3. Stream 的中間操作
    • 3.1 篩選與切片
    • 3.2 映射
    • 3.3 排序
  • 4. Stream 的終止操作
    • 4.1 匹配與查找
    • 4.2 歸約
    • 4.3 收集
  • 5.1 Optional類
    • 5.2 創建 Optional 的三種方式
    • 5.3 Optional 類中其他常用的方法
  • 6. 總結:
  • 7. 最后:

1. Stream 的概述

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

  • Java8 中有兩大最為重要的改變,第一個便是 Lambda 運算式,想要進一步了解的大家可以移步至 ?????? 函式式編程:Lambda 運算式_ChinaRainbowSea的博客-CSDN博客

;另外一個則為是我們這個主題了:Stream API 了,

  • Stream API 是在 java.util.stream 包下的,Stream 是把真正的函式式編程 風格引入到 Java 中,這時目前為止對 java 類別庫最好的補充了,因為 Stream API 可以極大的提供 Java程式員的生產力,讓程式員寫出更高效率,干凈,簡潔的代碼,
  • Stream 是 java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常復雜的查找,過濾和映射資料等操作,使用 Stream API 對集合資料進行操作,就類似于使用 SQL 執行的資料庫查詢 也可以使用 Stream API 的來并行執行操作,簡而言之,Stream API 提供了一種高效且易于使用的處理資料的方式,

1.1 為什么要使用Stream API

在實際開發種,專案中多資料源都是來自于 MySQ,Oracle 等資料庫的,但現在資料源可以更多了,有 MongDB,Radis 等,而這些 NoSQL 的資料就需要 Java層面去處理,

1.2 什么是 Stream

是資料渠道,用于操作資料源(集合,陣列等)所生成的元素序列,“集合講的是資料,Stream 講的是計算”

注意:

  • Stream 自己不會存盤元素,
  • Stream 不會改變源物件,相反,他們會回傳一個持有結果的新 Stream ,這一點和 String 不可變的特點類似,
  • Stream 操作是延遲執行的,這意味著它們會等到需要結果的時候才執行,

1.3 Stream 的操作三個步驟

  1. 創建 Stream

一個資料源(如:集合,陣列),獲取一個流

2.中間操作

一個中間操作鏈,對資料源的資料進行處理,

3. 終止操作(終端操作)

一旦執行終止操作,就執行中間操作鏈,并產生結果,之后,不會再被使用(也不可再使用),

在這里插入圖片描述

1.4 Stream 與 Colliection 的區別

Stream 和以前的Collection操作不同, Stream操作還有兩個基礎的特征:

  • Pipelining: 中間操作都會回傳流物件本身, 這樣多個操作可以串聯成一個管道, 這樣做可以對操作進行優化, 比如延遲執行.

  • 內部迭代: 以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進行迭代, 這叫做外部迭代, Stream提供了內部迭代的方式, 通過訪問者模式(Visitor)實作,

  • 當使用一個流的時候,通常包括三個基本步驟:獲取一個資料源(source)→ 資料轉換→執行操作獲取想要的結果,每次轉換原有 Stream 物件不改變,回傳一個新的 Stream 物件(可以有多次轉換),這就允許對其操作可以像鏈條一樣排列,變成一個管道,
  • StreamCollection 集合的主要區別:Collection 是一種靜態的記憶體資料結構,而 Stream 是有關計算的,前者是主要面向記憶體,存盤在記憶體中后者是主要是面向 CPU ,通過 CPU 實作計算的,

2. 創建 Stream 的四種方式

因為 Stream 是一個介面,所以我們無法通過 new 的方式創建該物件,

2.1 創建Stream 方式一:通過集合

Java8 中的 Collection 介面被擴展,提供了兩個獲取流 的方法:

  • default Stream stream() : 回傳一個順序流

  • default Stream parallelStream() : 回傳一個并行流

package blogs.blog13;


import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest {
    public static void main(String[] args) {
        List<Employee> employeeList = EmployeeData.getEmployees();
        //default Stream<E> stream(): 回傳一個順序流
        Stream<Employee> stream = employeeList.stream();
        System.out.println(stream);

        // default Stream<E> parallelStream : 回傳一個并行流
        Stream<Employee> employeeStream = employeeList.parallelStream();
        System.out.println(employeeStream);
    }
}

在這里插入圖片描述

2.2 創建 Stream 方式二:通過陣列

Java8 中的 Arrays 的靜態方法 stream() 可以獲取陣列流:

  • static Stream stream(T[] array): 回傳一個流

多載形式,能夠處理對應基本型別的陣列:

  • public static IntStream stream(int[] array)

  • public static LongStream stream(long[] array)

  • public static DoubleStream stream(double[] array)

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamAPITest {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5,6};

        // 呼叫 Arrays 類中的 static<T> stream(T[] array)回傳一個物件
        IntStream stream = Arrays.stream(arr);
        System.out.println(stream);

    }
}

在這里插入圖片描述

2.3 創建 Stream 的方式三: 通過 Stream 的 of()

可以呼叫Stream類靜態方法 of(), 通過顯示值創建一個流,它可以接收任意數量的引數,

  • public static Stream of(T... values) : 回傳一個流
import java.util.stream.Stream;


public class StreamAPITest {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
        System.out.println(stream);
    }
}

在這里插入圖片描述

2.4 創建 Stream 方式四: 創建無限流

可以使用靜態方法 Stream.iterate()Stream.generate(), 創建無限流,

  • 迭代

public static Stream iterate(final T seed, final UnaryOperator f)

  • 生成

public static Stream generate(Supplier s)

import java.util.stream.Stream;


public class StreamAPITest {
    public static void main(String[] args) {
        // 迭代:
        //public static<T> Stream<T> inerate(final T seed,final UnaryOperator<T> f)
        // 遍歷前 10 個偶數
        Stream.iterate(0,t->t+2).forEach(System.out::println);

        // 生成:
        // public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);

    }
}

在這里插入圖片描述

3. Stream 的中間操作

多個中間操作可以連接起來形成一個 流水線 ,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理!而終止操作時一次性全處理, 這樣的 稱為 惰性求值

3.1 篩選與切片

如下是關于 Stream 中間操作篩選與切片的一些常用的方法

  • Stream filter(Predicate<? super T> predicate); // 接收 Lambda 運算式,從流中排除某些元素
package blogs.blog13;

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        // 創建一個 Stream 物件
        Stream<Employee> stream = list.stream();
        // 使用 filter 進行一個篩選
        // boolean test(T t)
        // 篩選出:工資大于 7000 的 Employee 物件
        stream.filter(e->e.getSalary() > 7000).forEach(System.out::println);

    }
}

在這里插入圖片描述

注意: stream 和集合中的迭代器是一樣的,不可多次不同結構的使用, 再次使用時需要新建一個 stream 物件,才能使用,簡單的來說:就是 stream 物件一次只能對應一次操作,再進行一個新的操作時,必須新建一個 stream 物件才行,不然報java.lang.IllegalStateException例外,

在這里插入圖片描述

  • Stream distinct(); // 篩選,通過流所生成元素的 hashCode() 和 equals() 去除重復元素

注意: 使用該方法,因為涉及到篩選,需要對元素資料進行一個比較判斷,所以和集合同理:我們必須重寫其元素的 hashCode() 和 equals() 方法,不然報例外;

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        List<Employee> list = new ArrayList<Employee>();
        // distinct() 篩選,通過流所生成元素的 hashCode() 和 equals() 去除重復元素
        // 所以對應存盤的 Employee 物件需要重寫 hashCode() 和  equals()方法
        list.add(new Employee(1010,"劉強東",40,8000));
        list.add(new Employee(1010,"劉強東",40,8000));
        list.add(new Employee(1010,"劉強東",40,8000));
        list.add(new Employee(1010,"劉強東",20,8000));

        list.stream().distinct().forEach(System.out::println);


    }
}

在這里插入圖片描述

  • Stream limit(long maxSize); // 截斷流,使其元素不超過給定數量
import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        // 創建一個 Stream 物件
        Stream<Employee> stream = list.stream();

        // limit(n) 截斷流: 篩選出 list 集合中存盤的前3 個資訊
        stream.limit(3).forEach(System.out::println);

    }
}

在這里插入圖片描述

  • Stream skip(long n); // 跳過元素,回傳一個扔掉了前 n 個元素的流,若流中元素不足 n 個,則回傳一個空流,與 limit(n) 互補,

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        // skip(n) 跳過元素,回傳一個扔掉了前 n 個元素的流,若流中元素不足 n 個,則回傳一個 空
        // stream 不可二次使用,需要新建
        Stream<Employee> skip = list.stream().skip(3);
        skip.forEach(System.out::println);   // 該操作是終止操作,并運用了方法參考

    }
}

在這里插入圖片描述

3.2 映射

  • Stream map(Function<? super T,? extends R> mapper) 接收一個函式作為引數,該函式會被應用到每個元素上,并將其映射成一個新的元素, 注意: 回傳的是一個新的物件,不會修改原本的資料資訊的,

在這里插入圖片描述


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("aa","bb","cc");

        // 創建一個 Stream 物件
        Stream<String> stream = list.stream();
        Stream<String> stringStream = stream.map(s -> s.toUpperCase());  // toUpperCase() 將字母轉換為大寫的
        stringStream.forEach(System.out::println);  // Stream  終止操作
    }
}

在這里插入圖片描述


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {

    // 將字串的多個字符構造的從集合轉換為單個字串并存盤到 List 集合中
    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();

        for (Character character : str.toCharArray()) { // toCharArray()將一個字串拆分為單個字符
            list.add(character);
        }

        return list.stream();
    }

    public static void main(String[] args) {
        // flatMap(Function f) 接收一個函式作為引數,將流中的每個值都換成另一個流,然后把所有的
        // 資料組成一個資料
        List<String> list = Arrays.asList("aa","AA","bb");

        Stream<String> stream = list.stream();
        Stream<Character> characterStream = stream.flatMap(StreamAPITest02::fromStringToStream); // 方法參考
        characterStream.forEach(System.out::println);


    }
}

在這里插入圖片描述

舉例: 練習:獲取員工姓名長度大于 3 的員工的姓名:

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        List<Employee> employees = EmployeeData.getEmployees();
        // 創建 stream 物件
        Stream<Employee> stream = employees.stream();
        // 獲取到一個關于 Employee 物件中的 有關 name 屬性的 Stream 物件
        Stream<String> stringStream = stream.map(e -> e.getName());
        // 獲取到該 Stream 物件中 name 長度大于 3 的名字
        Stream<String> stringFilter = stringStream.filter(e -> e.length() > 3);
        stringFilter.forEach(System.out::println);

    }
}

在這里插入圖片描述

3.3 排序

  • Stream sorted() 產生一個新流,其中按自然順序排序
  • Stream sorted(Comparator<? super T> comparator) 產生一個新流,其中按比較器順序排序(也就是定制排序),

注意:這里的排序要排序的元素資訊,必須實作 Comparable 介面或者是 Comparator 定制排序 ,不然報例外,關于這部分排序內容,想要多加了解的,可以移步至:?????? 比較器: Comparable 與 Comparator 區別_ChinaRainbowSea的博客-CSDN博客

舉例:soreted() 運用自然排序 ,排序的元素實作了 comparable 介面


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        // sorted -- 自然排序
        // 注意排序:需要實作  Comparable 介面
        // 注意泛型不能放基本資料型別
        List<Integer> list = Arrays.asList(12,56,3,2,1);
        // 創建 Stream 物件
        Stream<Integer> stream = list.stream();
        stream.forEach(System.out::println);
    }
}

在這里插入圖片描述

舉例: sorted(comparator com ) 定制排序 通過年齡排序,默認是升序的 > 0 回傳 1


import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest02 {
    public static void main(String[] args) {
        // sorted(comparator  com ) 定制排序 通過年齡排序,默認是升序的 > 0 回傳 1,
        List<Employee> employees = EmployeeData.getEmployees();
        // 創建 Stream 物件
        Stream<Employee> stream = employees.stream();
        Stream<Employee> sorted = stream.sorted((e1, e2) -> {
            int compare = Integer.compare(e1.getAge(), e2.getAge());  // 年齡排序

            if (compare != 0) {
                return compare;
            } else { // 年齡一致,再通過比較器進一步排序,比較薪資排序
                return Double.compare(e1.getSalary(), e2.getSalary());
            }
        });
        sorted.forEach(System.out::println);

    }
}

在這里插入圖片描述

4. Stream 的終止操作

終端操作會從流水線 生成的結果,其結果可以是任何不是流的值,例如:list,Integer,甚至是 void

注意: Stream 流一旦執行了終止操作后,就不能再使用了,

4.1 匹配與查找

  • allmathc()檢查Stream 流中內容中是否匹配所有元素
boolean allMatch(Predicate<? super T> predicate); // 檢查是否匹配所有元素

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;

public class StreamAPITest03 {
    /**
     * allMatch(Predicate p) 檢查是否匹配所有元素,
     * 練習:是否所有的員工的年齡都大于 18
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();

        boolean b = list.stream().anyMatch(e -> e.getAge() > 18);
        System.out.println(b);

    }
}

在這里插入圖片描述

  • anyMatch(Predicate p) 檢查 Stream 流中內容中是否至少匹配一個元素,
boolean anyMatch(Predicate<? super T> predicate); 
import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;

public class StreamAPITest03 {
    /**
     * anyMath(Predicate p) 檢查是否至少匹配一個元素:
     * 練習: 是否存在元素的工資大于 10000
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        boolean b = list.stream().anyMatch(e -> e.getSalary() > 1000);
        System.out.println(b);

    }
}

在這里插入圖片描述

  • noneMatch(Predicate p) 檢查Stream 流中內容中是否沒有匹配所有元素
boolean noneMatch(Predicate<? super T> predicate);

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * noneMatch(Predicate p) 檢查是否沒有匹配的元素,
     * 練習: 是否存在員工姓 "雷"
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        // String 中的startsWith 表示該字串中是否含有該字符內容,有回傳 true,沒有回傳 fasle
        boolean b = stream.noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(b);
    }
}

在這里插入圖片描述

  • findFirst() 回傳Stream 流中內容的第一個元素

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * findFirst 回傳第一個元素
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        Optional<Employee> first = stream.findFirst();
        System.out.println(first);
        
    }
}

在這里插入圖片描述

  • findAny() 回傳當前Stream 流中內容中中任意元素

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * findAny 回傳當前流中的任意元素
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        Optional<Employee> any = stream.findAny();
        System.out.println(any);
    }
}

在這里插入圖片描述

  • count() 回傳Stream 流中內容中中元素總數

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * count 回傳流中元素的總個數
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        long count = stream.count();
        System.out.println(count);
    }
}

在這里插入圖片描述

  • max(Comparator c) 回傳Stream 流中內容中中最大值

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * max(Comparator c) 回傳流中最大值
     * 練習回傳最高的工資,
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        // 創建一個有關于 Employee 物件的 屬性為salary的 Stream 流
        Stream<Double> doubleSalary = stream.map(e -> e.getSalary());
        Optional<Double> max = doubleSalary.max(Double::compareTo);// 方法參考
        System.out.println(max);
    }
}

在這里插入圖片描述

  • min(Comparator c) 回傳Stream 流中內容中中最小值

import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * max(Comparator c) 回傳流中最大值
     * 練習回傳最低的工資,
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        Stream<Employee> stream = list.stream();
        // 創建一個有關于 Employee 物件的 屬性為salary的 Stream 流
        Stream<Double> doubleSalary = stream.map(e -> e.getSalary());
        Optional<Double> min = doubleSalary.min(Double::compareTo);// 方法參考
        System.out.println(min);
    }
}

在這里插入圖片描述

  • forEach(Consumer c) 內部迭代(使用 Collection ) 介面需要用戶去做迭代,稱為 外部迭代,相反 ,Stream API 使用內部迭代—— 它幫你把迭代做了
import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {

    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        list.stream().forEach(System.out::println);

        System.out.println("****************************");
        // 集合的遍歷操作
        list.forEach(System.out::println);
    }
}

在這里插入圖片描述

4.2 歸約

如下是關于歸約常用方法:

  • reduce(BinaryOperator b) 可以將流中元素結合起來,比如: sum,count 得到一個值,回傳 Optional
Optional<T> reduce(BinaryOperator<T> accumulator); // 
  • reduce(T iden,BinaryOperator b) 可以將流中元素反復結合起來,得到一個值,回傳 T
T reduce(T identity, BinaryOperator<T> accumulator);  // 

補充: mapreduce 的連接通常為 map-reduce 模式,因 Google 用它來進行網路搜索而出名,

舉例:


import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * reduce(T identity, BinaryOperator ) 可以將流中元素反復結合起來,得到一個值,回傳
     * 練習: 計算 1-10 的自然數的和
     */
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        Stream<Integer> stream = list.stream();
        Integer reduce = stream.reduce(0, Integer::sum);
        System.out.println(reduce);
    }
}

在這里插入圖片描述

舉例:


import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class StreamAPITest03 {
    /**
     * reduce(BinaryOperator) 可以將流中元素反復的結合起來,得到一個值,回傳Optional<T>
     * 練習: 計算公司所有員工的工資的總和
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        // 獲取到 Employees 員工工資的 Stream 流物件
        Stream<Double> streamSalary = list.stream().map(e -> e.getSalary());
        Optional<Double> reduce = streamSalary.reduce((d1, d2) -> d1 + d2);
        System.out.println(reduce);
    }
}

在這里插入圖片描述

4.3 收集

Collect(Collectior c) : 將流轉換為其他形式,接收一個 Collector 介面的實作,用于 Stream 中元素做匯總的方法,

<R,A> R collect(Collector<? super T,A,R> collector);

Collector 介面中方法的實作決定了如何對流執行收集的操作(如收集到 List ,Set,Map),另外,Collectior 實用類提供了很多靜態方法,可以方便創建常見收集器實體,具體方法與實體如下表:

在這里插入圖片描述

在這里插入圖片描述


import day33.java.Employee;
import day33.java.EmployeeData;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamAPITest03 {

    /**
     * collect(Collector c) 將流轉換為其他形式,接收一個Collector 介面的實作,
     * 用于給 Stream 中
     * 練習1 查找工資大于 6000 的員工,結果回傳為一個 List 或 set
     */
    public static void main(String[] args) {
        List<Employee> list = EmployeeData.getEmployees();
        // 獲取到一個工資大于 6000 的 Stream 流
        Stream<Employee> employeeStream = list.stream().filter(e->e.getSalary() > 6000);
        List<Employee> collect = employeeStream.collect(Collectors.toList());
        collect.forEach(System.out::println);
    }
}

在這里插入圖片描述

5.1 Optional類

在這里插入圖片描述

在這里插入圖片描述

到目前為止,臭名昭著的空指標例外是導致Java應用程式失敗的最常見原因,以前,為了解決空指標例外,Google公司著名的Guava專案引入了Optional類,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵程式員寫更干凈的代 碼,受到Google Guava的啟發,Optional類已經成為Java 8類別庫的一部分,

  • Optional 類(java.util.Optional) 是一個容器類,它可以保存型別T的值,代表這個值存在,或者僅僅保存null,表示這個值不存在,原來用 null 表示一個值不 存在,現在 Optional 可以更好的表達這個概念,并且可以避免空指標例外,

  • Optional類的Javadoc描述如下:這是一個可以為null的容器物件,如果值存在 則isPresent()方法會回傳true,呼叫get()方法會回傳該物件,

Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測

5.2 創建 Optional 的三種方式

創建Optional類物件的方法:

  • Optional.of(T t) : 創建一個 Optional 實體,t 必須非空,

在這里插入圖片描述

  • Optional.empty() : 創建一個空的 Optional 實體,
import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args) {
        Optional<Girl> optional = Optional.empty();
        System.out.println(optional);
    }
}

在這里插入圖片描述

  • Optional.ofNullable(T t): t 可以為null,

import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args) {
        Girl girl = new Girl();
        girl = null;
        Optional<Girl> optional = Optional.ofNullable(girl);  // ofNullable 中的 t 引數可以為空
        System.out.println(optional);
    }
}

在這里插入圖片描述

5.3 Optional 類中其他常用的方法

判斷Optional容器中是否包含物件:

  • boolean isPresent() : 判斷是否包含物件

  • void ifPresent(Consumer consumer) : 如果有值,就執行Consumer介面的實作代碼,并且該值會作為引數傳給它,

獲取Optional容器的物件:

  • T get(): 如果呼叫物件包含值,回傳該值,否則拋例外

  • T orElse(T other) : 如果有值則將其回傳,否則回傳指定的other物件,

  • T orElseGet(Supplier other) : 如果有值則將其回傳,否則回傳由Supplier介面實作提供的物件,

  • T orElseThrow(Supplier exceptionSupplier) : 如果有值則將其返 回,否則拋出由Supplier介面實作提供的例外,


import java.util.Optional;

public class OptionalTest {
    // orElse(T t) 如果單前的 Optional 內部封裝的t是非空的,則回傳內部的 t,
    // 如果內部的 t是空的,則回傳orElse()方法中的引數t1.
    // 使用 Optional 類的 getGirName()
    public static String getGirName2(Girl girl) {
        Optional<Girl> optional = Optional.ofNullable(girl);
        // 如果 Optional 中的 girl 為 null ,則使用 如下的 new Girl(new Boy("肖戰")) 替換就不為空了
        // 不為 null 是不會發生替換的,使用原來的就可以了,
        Girl girl2 = optional.orElse(new Girl(new Boy("肖戰")));
        Boy boy = girl2.getBoy();

        /*Optional<Boy> boyOptional = Optional.ofNullable(boy);
        Boy boy1 = boyOptional.orElse(new Boy("王一博"));*/

        return boy.getName();
    }

    public static void main(String[] args) {
        Girl girl = null;
        String girName2 = getGirName2(girl);
        System.out.println(girName2);

        Girl girl2 = new Girl(new Boy("王一博"));
        String girName = getGirName2(girl2);
        System.out.println(girName);

    }
}

在這里插入圖片描述

6. 總結:

  1. Stream 是資料渠道,用于操作資料源(集合,陣列等)所生成的元素序列,“集合講的是資料,Stream 講的是計算”
  2. Stream 的操作三個步驟:創建 Strem 流,中間操作,終止操作,
  3. Stream 創建的四種方式
  4. stream 和集合中的迭代器是一樣的,不可多次不同結構的使用, 再次使用時需要新建一個 stream 物件,才能使用,簡單的來說:就是 stream 物件一次只能對應一次操作,再進行一個新的操作時,必須新建一個 stream 物件才行,不然報java.lang.IllegalStateException例外,
  5. Stream 流一旦執行了終止操作后,就不能再使用了,
  6. Stream 自己不會存盤元素,
  7. Stream 不會改變源物件,相反,他們會回傳一個持有結果的新 Stream ,這一點和 String 不可變的特點類似,
  8. Stream 操作是延遲執行的,這意味著它們會等到需要結果的時候才執行,
  9. Optional 類(java.util.Optional) 是一個容器類,它可以保存型別T的值,代表這個值存在,或者僅僅保存null,表示這個值不存在,原來用 null 表示一個值不 存在,現在 Optional 可以更好的表達這個概念,并且可以避免空指標例外,

7. 最后:

限于自身水平,其中存在的錯誤,希望大家給予指教,韓信點兵——多多益善,謝謝大家,江湖再見,后會有期 !!!

在這里插入圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545914.html

標籤:其他

上一篇:統一日志輸出列印POST請求引數

下一篇:07字串操作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more