小夥伴們好呀,我是 小羊,今天來和大家分享下這個 Stream 。
目錄
什麼是流呢?
想了好久也不知道怎麼表述,感覺很抽象,就是一個很好用的工具。
認真點說辭
對 Java集合 的增強,提供了 過濾,計算,轉換 等聚合操作,使用起來友善快捷。
詳解
來自 https://www.logicbig.com/tutorials/core-java-tutorial/java-util-stream/stream-api-intro.html
流 和 集合 的不同點
為了弄明白這個 stream 是啥,我還特意去翻看了 Java SE 的文檔,今年第一次打開 哈哈哈
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
- 流不是資料結構,不存儲資料
- 流不改變資料源的資料,比如 filter 一個集合時,最後是傳回一個新集合,而不是删除原集合中的對象
- 流的 API 分為 中間操作 和 終端操作,中間操作是惰性的,遇到終端操作才真正執行
- 流是無限的,集合是有限的,可以通過 limit ,findFirst 等 短路 API 來讓它快點執行完
- 是一次性的,使用後就關閉了,需要重新建立,和 Iterator 一樣。
流的建立
看文檔裡有很多種建立方式,stream(),Stream.of(),Arrays.stream() 等,不過我平時使用最多的還是 stream() 這種。
這裡要稍微注意下這個 Stream.of() 和 stream() 的差別
Stream.of() 會把傳進去的參數當作 元素 處理,而 stream() 是 Collection 接口中新增的預設方法,它本來就是用來處理 集合中的每一個元素 的。
但是 Stream.of() 也可以利用 flatMap 這個函數來展開集合中的元素,達成相應的目的
// Stream.of(data) 把集合當作整體處理,不是處理其中的元素
// stream(data) 處理集合中的元素
int[] data = {4, 5, 3, 6, 2, 5, 1};
Stream.of(data)
.flatMap(e -> Arrays.stream(e).boxed()).collect(Collectors.toList())
.forEach(System.out::println);
Arrays.stream(data).boxed().collect(Collectors.toList()).forEach(System.out::println);
中間操作
這裡有下面兩種狀态區分
- 無狀态:無需等待上一步的操作
- 有狀态:需要擷取上一步操作的所有元素後才可以進行下一步操作,會多疊代一次,就比如 sorted,會将之前的所有元素進行排序,然後再進行下一步操作
這部分的 API 如下,也比較簡單,文末再給個小例子
終端操作
這裡就是産生結果的了。
API 分為 短路操作與否。
數組,集合,包裝類,基本資料類型之間的轉換
這個我也是老忘記~
// int[] 轉 List<Integer>
// 這裡用到了 數組流 的建立方式,通過 Arrays.stream(data) 将其變成 IntStream,調用 boxed 變成包裝類,最後轉成集合。
List<Integer> list1 = Arrays.stream(data).boxed().collect(Collectors.toList());
// int[] 轉 Integer[]
// 同上,轉成數組用 toArray
Integer[] integer1 = Arrays.stream(data).boxed().toArray(Integer[]::new);
// List<Integer> 轉 Integer[]
// 集合轉數組,直接用 toArray 即可
Integer[] integers2 = list1.toArray(new Integer[0]);
// List<Integer> 轉 int[]
// 裝箱拆箱,得通過 IntStream 來實作
int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();
// Integer[] 轉 int[]
// 同樣的,裝箱拆箱,得通過 IntStream 來實作
int[] arr2 = Arrays.stream(integer1).mapToInt(Integer::valueOf).toArray();
// Integer[] 轉 List<Integer>
List<Integer> list2 = Arrays.asList(integer1);
小例子
public static void main(String[] args) {
String str = "Java4ye";
Student aStud = new Student(1, "a");
Student bStud = new Student(2, "b");
Student cStud = new Student(3, null);
// 集合的建立 一
List<Student> collect1 = Stream.of(aStud, bStud, cStud).collect(Collectors.toList());
collect1.forEach(System.out::println);
// 集合的建立 二
List<Student> studentList = new ArrayList<>();
studentList.add(aStud);
studentList.add(bStud);
studentList.add(cStud);
List<String> studNameList = studentList.stream()
.map(Student::getName)
.filter(Objects::nonNull)
.map(String::toUpperCase)
.sorted()
.map(e -> e + "c")
.collect(Collectors.toList());
studNameList.forEach(System.out::println);
// toMap 要注意 Duplicate key 的問題,需要 merge 處理,其他的 map 等擷取屬性時,要提防 null
Map<String, Student> collect = studentList.stream()
.collect(
Collectors.toMap(
Student::getName,
e -> e,
(a, b) -> {
if (a.getAge() > b.getAge()) {
return a;
}
return b;
}
)
);
collect.forEach((s, student) -> System.out.println(student));
}
IDEA 自帶的 debug 可以清楚看到每一步擷取到的資料
對 API 不熟悉的,可以看看這個部落客的例子
https://blog.csdn.net/mu_wind/article/details/109516995#t1
贊
總結
看完之後,要記得
stream 是一次性的,不是資料結構,不存儲資料,不改變源資料.。
API 分為終端和中間操作,中間操作是惰性的,碰到終端才去執行。
同時中間操作有無狀态和有狀态之分,有狀态需要更改上一步操作獲得的所有元素,才可以進行下一步操作,比如 排序 sorted,去重 distinct,跳過 skip,限制 limit 這四個,需要多疊代一次。
終端操作有短路與否之分,短路操作有 anyMatch, allMatch, noneMatch, findFirst, findAny
不過,現在我對它的源碼更感興趣了,找個時間再研究研究✍
喜歡的小夥伴記得關注點點贊哦,全網同名[狗頭]