函式編程:強大的 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 的操作三個步驟
- 創建 Stream
一個資料源(如:集合,陣列),獲取一個流
2.中間操作
一個中間操作鏈,對資料源的資料進行處理,
3. 終止操作(終端操作)
一旦執行終止操作,就執行中間操作鏈,并產生結果,之后,不會再被使用(也不可再使用),

1.4 Stream 與 Colliection 的區別
Stream 和以前的Collection操作不同, Stream操作還有兩個基礎的特征:
-
Pipelining: 中間操作都會回傳流物件本身, 這樣多個操作可以串聯成一個管道, 這樣做可以對操作進行優化, 比如延遲執行.
-
內部迭代: 以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進行迭代, 這叫做外部迭代, Stream提供了內部迭代的方式, 通過訪問者模式(Visitor)實作,
- 當使用一個流的時候,通常包括三個基本步驟:獲取一個資料源(source)→ 資料轉換→執行操作獲取想要的結果,每次轉換原有 Stream 物件不改變,回傳一個新的 Stream 物件(可以有多次轉換),這就允許對其操作可以像鏈條一樣排列,變成一個管道,
- Stream 和 Collection 集合的主要區別: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); //
補充: map 和 reduce 的連接通常為 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. 總結:
- Stream 是資料渠道,用于操作資料源(集合,陣列等)所生成的元素序列,“集合講的是資料,Stream 講的是計算” ,
- Stream 的操作三個步驟:創建 Strem 流,中間操作,終止操作,
- Stream 創建的四種方式
- stream 和集合中的迭代器是一樣的,不可多次不同結構的使用, 再次使用時需要新建一個 stream 物件,才能使用,簡單的來說:就是 stream 物件一次只能對應一次操作,再進行一個新的操作時,必須新建一個 stream 物件才行,不然報
java.lang.IllegalStateException例外, - Stream 流一旦執行了終止操作后,就不能再使用了,
- Stream 自己不會存盤元素,
- Stream 不會改變源物件,相反,他們會回傳一個持有結果的新 Stream ,這一點和 String 不可變的特點類似,
- Stream 操作是延遲執行的,這意味著它們會等到需要結果的時候才執行,
- Optional 類(java.util.Optional) 是一個容器類,它可以保存型別T的值,代表這個值存在,或者僅僅保存null,表示這個值不存在,原來用 null 表示一個值不 存在,現在 Optional 可以更好的表達這個概念,并且可以避免空指標例外,
7. 最后:
限于自身水平,其中存在的錯誤,希望大家給予指教,韓信點兵——多多益善,謝謝大家,江湖再見,后會有期 !!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545914.html
標籤:其他
上一篇:統一日志輸出列印POST請求引數
下一篇:07字串操作
