stream and lambda(8) - 中間操作之篩選操作(filter、distinct、limit、skip)
Stream 流的資料處理過程中,少不的一點就是對資料的篩選。在以前的程式設計方式裡,對集合資料的篩選,要經過遍歷、判斷,搞不好過程中再遇到個異常,比如邊遍歷邊 remove。而 Stream 提供的資料篩選方法,簡化我們寫法的同時,也可以有效避免複雜編碼過程中不經意間寫的 bug。
filter
方法定義
Stream<T> filter(Predicate<? super T> predicate);
filter
方法,通過傳入的 Predicate
對流內的元素進行過濾,可以將不滿足條件的元素過濾掉。
關於 Predicate
,我們也在函式式介面的內容裡講過:傳送門
使用舉例
public void filterTest() { Stream<Integer> stream = Stream.of(1, 23, 4, 5, 6); List<Integer> result = stream.filter(i -> i > 5).collect(Collectors.toList()); System.out.println(result); }
執行結果如下,此時已將元素過濾:
[23, 6]
distinct
方法定義
Stream<T> distinct();
distinct
方法,無入參,呼叫後將流內的重複元素去除。
使用舉例
public void distinctTest() { Stream<Integer> stream = Stream.of(1, 1, 2, 2, 4); List<Integer> result = stream.distinct().collect(Collectors.toList()); System.out.println(result); }
執行結果如下:
[1, 2, 4]
元素到底是怎麼過濾的
雖然上面執行結果已經將元素過濾掉,但我們還是不清楚元素到底是怎麼被過濾掉的。如果是對自定義物件類的元素過濾,我們可能無法有效預測過濾結果。
經過原始碼檢視,看到如下片斷:
<P_IN> Node<T> reduce(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) { TerminalOp<T, LinkedHashSet<T>> reduceOp = ReduceOps.<T, LinkedHashSet<T>>makeRef(LinkedHashSet::new, LinkedHashSet::add, LinkedHashSet::addAll); return Nodes.node(reduceOp.evaluateParallel(helper, spliterator)); }
基本可以看出,去重是通過 Set
來去重的,而 Set
內部是通過 hashcode
和 equals
來去重。更詳細的內容,可以參考以前的文章: Java集合分析之Set-以HashSet為例
。
如果我們不想通過 hashcode
和 equals
去重怎麼辦呢?簡單,可以用 ConcurrentHashMap
記錄 key 是否已出現,配合 filter
方法來過濾。
limit
方法定義
Stream<T> limit(long maxSize);
limit
方法通過傳入留取的最大數,來過濾流中的元素。
使用舉例
public void limitTest() { Stream<Integer> stream = Stream.of(1, 3, 5, 7, 5); List<Integer> result = stream.limit(4).collect(Collectors.toList()); System.out.println(result); }
執行結果如下:
[1, 3, 5, 7]
skip
方法定義
Stream<T> skip(long n);
skip
方法通過傳入跳過的元素數量,來過濾流中的元素。和 limit
剛好組成一對,一個掐頭,一個去尾。
使用舉例
public void skipTest() { Stream<Integer> stream = Stream.of(1, 3, 5, 7, 5); List<Integer> result = stream.skip(3).collect(Collectors.toList()); System.out.println(result); }
執行結果如下:
[7, 5]
總結
-
本次重點講了
Stream
中間操作的元素篩選部分。 -
skip
和limit
,兩個操作一個掐頭,一個去尾。 -
filter
根據傳入的判斷條件來過濾元素。 -
distinct
根據hashcode
和equals
來去重。如果想根據其他內容來去重,可以使用filter
來實現。
注:本文配套程式碼可在 github
檢視: stream-and-lambda
「其他文章」
- stream and lambda(18) - 終止操作之 stream 收集器 collectors
- stream and lambda(15) - 終止操作之 stream 陣列操作 toArray
- stream and lambda(13) - 終止操作之計數 count 與比較 min、max
- stream and lambda(12) - 終止操作之查詢與匹配(findAny、findFirst、allMatch、anyMatch、noneMatch)
- stream and lambda(11) - Optional 簡介
- stream and lambda(10) - 中間操作之排序sorted與除錯peek
- stream and lambda(9) - 中間操作之map操作(map、flatmap)
- stream and lambda(8) - 中間操作之篩選操作(filter、distinct、limit、skip)
- stream and lambda(7) - stream 的建立
- stream and lambda(6) - stream 簡介
- stream and lambda(5) - lambda 表示式最佳實踐
- stream and lambda(3) - jdk 提供的函式式介面
- stream and lambda(2) - 函式式介面簡介
- stream and lambda(1) - lambda 簡介