Stream流式處理解釋
Stream流
Stream 中文稱為 “流”,通過將集合轉換為這麼一種叫做 “流” 的元素序列,通過宣告性方式,能夠對集合中的每個元素進行一系列並行或序列的流水線操作。
函數語言程式設計帶來的好處尤為明顯。這種程式碼更多地表達了業務邏輯的意圖,而不是它的實現機制。易讀的程式碼也易於維護、更可靠、更不容易出錯。
面對一對多結構,查詢主實體時需要附帶主實體的子實體列表怎麼寫?查出主列表,迴圈差子列表
List的Stream流操作可以簡化我們的程式碼,減少程式執行的壓力,應對上面的問題,以前的話是先查出對應的list資料,然後根據取到集合中id去查詢對應的子實體中資料,接著在放入對應的集合中去,key值表示主實體的id,value值表示對應主實體id查到的結合資料,這樣就會三次foreach迴圈組裝資料,會很麻煩,當資料量大的時候,會增加程式執行的負荷,造成執行緩慢。所以,流式操作代替我們的這一堆操作,提高了程式碼的簡易性,可維護性,可靠性,更不容易出錯。
列子
首先我們先建立一個 Person 泛型的 List
List<UserPerson> list = new ArrayList<>(); list.add(new UserPerson("jack", 20)); list.add(new UserPerson("mike", 25)); list.add(new UserPerson("tom", 30));
UserPerson 類包含年齡和姓名兩個成員變數
public class UserPonson{ private String name; private int age; }
- stream() / parallelStream()
最常用到的方法,將集合轉換為流
List list = new ArrayList(); // return Stream<E> list.stream();
而 parallelStream() 是並行流方法,能夠讓資料集執行並行操作
- filter(T -> boolean)
保留 boolean 為 true 的元素
保留年齡為 20 的 userPerson 元素 list = list.stream() .filter(person -> person.getAge() == 20) .collect(toList()); 列印輸出 [UserPerson{name='jack', age=20}]
collect(toList()) 可以把流轉換為 List 型別
- distinct()
去除重複元素,這個方法是通過類的 equals 方法來判斷兩個元素是否相等的
如例子中的 UserPerson 類,需要先定義好 equals 方法,不然類似[UserPerson{name='jack', age=20}, UserPerson{name='jack', age=20}] 這樣的情況是不會處理的 - sorted() / sorted((T, T) -> int)
如果流中的元素的類實現了 Comparable 介面,即有自己的排序規則,那麼可以直接呼叫 sorted() 方法對元素進行排序,如 Stream<Integer>
反之, 需要呼叫 sorted((T, T) -> int) 實現 Comparator 介面
根據年齡大小來比較: list = list.stream() .sorted((p1, p2) -> p1.getAge() - p2.getAge()) .collect(toList());
當然這個可以簡化為
list = list.stream()
.sorted(Comparator.comparingInt(UserPerson::getAge))
.collect(toList());
- limit(long n)
返回前 n 個元素
list = list.stream() .limit(2) .collect(toList()); 列印輸出 [UserPerson{name='jack', age=20}, UserPerson{name='mike', age=25}]
- skip(long n)
去除前 n 個元素
list = list.stream() .skip(2) .collect(toList()); 列印輸出 [UserPerson{name='abc', age=30}]
tips:
用在 limit(n) 前面時,先去除前 m 個元素再返回剩餘元素的前 n 個元素
limit(n) 用在 skip(m) 前面時,先返回前 n 個元素再在剩餘的 n 個元素中去除 m 個元素
list = list.stream() .limit(2) .skip(1) .collect(toList()); 列印輸出 [UserPerson{name='mike', age=25}]
- map(T -> R)
將流中的每一個元素 T 對映為 R(類似型別轉換)
List<String> newlist = list.stream().map(UserPerson::getName).collect(toList());
newlist 裡面的元素為 list 中每一個 UserPerson 物件的 name 變數
- flatMap(T -> Stream<R>)
將流中的每一個元素 T 對映為一個流,再把每一個流連線成為一個流
List<String> list = new ArrayList<>(); list.add("aaa bbb ccc"); list.add("ddd eee fff"); list.add("ggg hhh iii"); list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());
上面例子中,我們的目的是把 List 中每個字串元素以" "分割開,變成一個新的 List<String>。
首先 map 方法分割每個字串元素,但此時流的型別為 Stream<String[ ]>,因為 split 方法返回的是 String[ ] 型別;所以我們需要使用 flatMap 方法,先使用Arrays::stream將每個 String[ ] 元素變成一個 Stream<String> 流,然後 flatMap 會將每一個流連線成為一個流,最終返回我們需要的 Stream<String>
- anyMatch(T -> boolean)
流中是否有一個元素匹配給定的 T -> boolean 條件
是否存在一個 person 物件的 age 等於 20:
boolean b = list.stream().anyMatch(person -> person.getAge() == 20);
- allMatch(T -> boolean)
流中是否所有元素都匹配給定的 T -> boolean 條件 - noneMatch(T -> boolean)
流中是否沒有元素匹配給定的 T -> boolean 條件 - findAny() 和 findFirst()
findAny():找到其中一個元素 (使用 stream() 時找到的是第一個元素;使用 parallelStream() 並行時找到的是其中一個元素)
findFirst():找到第一個元素
值得注意的是,這兩個方法返回的是一個 Optional<T> 物件,它是一個容器類,能代表一個值存在或不存在,這個後面會講到
- reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)
用於組合流中的元素,如求和,求積,求最大值等
計算年齡總和: int sum = list.stream().map(UserPerson::getAge).reduce(0, (a, b) -> a + b); 與之相同: int sum = list.stream().map(UserPerson::getAge).reduce(0, Integer::sum);
其中,reduce 第一個引數 0 代表起始值為 0,lambda (a, b) -> a + b 即將兩值相加產生一個新值
同樣地:
計算年齡總乘積: int sum = list.stream().map(UserPerson::getAge).reduce(1, (a, b) -> a * b);
當然也可以
Optional<Integer> sum = list.stream().map(UserPerson::getAge).reduce(Integer::sum);
即不接受任何起始值,但因為沒有初始值,需要考慮結果可能不存在的情況,因此返回的是 Optional 型別
- count()
返回流中元素個數,結果為 long 型別 - collect()
收集方法,我們很常用的是 collect(toList()),當然還有 collect(toSet()) 等,引數是一個收集器介面,這個後面會另外講 - forEach()
返回結果為 void,很明顯我們可以通過它來幹什麼了,比方說:
### 16. unordered()
還有這個比較不起眼的方法,返回一個等效的無序流,當然如果流本身就是無序的話,那可能就會直接返回其本身
列印各個元素:
list.stream().forEach(System.out::println);
再比如說 MyBatis 裡面訪問資料庫的 mapper 方法:
向資料庫插入新元素:
list.stream().forEach(PersonMapper::insertPerson);
文章來源:https://www.jianshu.com/p/24af4f3ab046