還在用迭代器處理集合嗎?試試Stream,真香
阿新 • • 發佈:2020-05-08
## 前言
上一篇部落格[一文帶你深入瞭解 Lambda 表示式和方法引用](https://www.cnblogs.com/keatsCoder/p/12839050.html)我給大家介紹了 Java8 函式式特性中的 Lambda,這篇文章我將繼續討論 stream 流的用法
宣告:本文首發於部落格園,作者:後青春期的Keats;地址:https://www.cnblogs.com/keatsCoder/ 轉載請註明,謝謝!
## Show Time
首先給大家看一段程式碼,讓大家直觀感受下 Java7 和 Java8 遍歷處理集合的不同
Dish 是一個菜餚物件,calories 屬性表示該菜品的卡路里值,name 則是菜品的名稱。我們需要過濾出卡路里小於400、然後根據卡路里值升序、接著拿到他們的名稱列表並返回
Java7
```java
public static List getLowCaloricDishesNamesInJava7(List dishes){
List lowCaloricDishes = new ArrayList<>();
for(Dish d: dishes){
if(d.getCalories() < 400){
lowCaloricDishes.add(d);
}
}
List lowCaloricDishesName = new ArrayList<>();
Collections.sort(lowCaloricDishes, new Comparator() {
public int compare(Dish d1, Dish d2){
return Integer.compare(d1.getCalories(), d2.getCalories());
}
});
for(Dish d: lowCaloricDishes){
lowCaloricDishesName.add(d.getName());
}
return lowCaloricDishesName;
}
```
Java8
```java
public static List getLowCaloricDishesNamesInJava8(List dishes){
return dishes.stream()
.filter(d -> d.getCalories() < 400)
.sorted(comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
}
```
如果需要多核並行處理,則只需呼叫 `dishes.parallelStream()` 即可
在 Java8 之前,程式設計師需要通過 2次遍歷 + 一次集合排序才能完成的工作,Java8 只需要一個鏈式呼叫就可以解決。這就是 stream 的強大之處
![img](https://img2020.cnblogs.com/blog/1654189/202005/1654189-20200507223039981-1259589654.jpg)
## 認識流
### 流是什麼
流是 Java API 的新成員,允許程式設計師以宣告式的方式處理集合資料,並且支援鏈式呼叫、支援並行處理。用流處理的集合資料高效且易讀。
### 流與集合的異同
1. 集合的主要功能是以一定的時間和空間複雜度儲存和訪問元素,而流主要是用於元素計算
2. 集合中的元素可以隨意新增和刪除,而流不能新增和刪除元素
3. 流的元素是按需計算的,只有當用到時他才會參與計算,而集合中的元素必須提前全都準備好
4. 流只能遍歷一次,下面的程式碼會報錯 `java.lang.IllegalStateException: stream has already been operated upon or closed` 流已經被消費掉
```java
List names = Arrays.asList("Java8", "Lambdas", "In", "Action");
Stream s = names.stream();
s.forEach(System.out::println);
s.forEach(System.out::println);
```
5. 集合採用外部迭代,流採用內部迭代。內部迭代意味著 Java 可以替你選擇更優的迭代策略和並行處理。而外部迭代如果程式設計師想著做個更有的迭代/採用並行就相當於“下次一定”