1. 程式人生 > >還在用迭代器處理集合嗎?試試Stream,真香

還在用迭代器處理集合嗎?試試Stream,真香

## 前言 上一篇部落格[一文帶你深入瞭解 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 可以替你選擇更優的迭代策略和並行處理。而外部迭代如果程式設計師想著做個更有的迭代/採用並行就相當於“下次一定”