1.簡介
本文將討論Java Stream API的skip()和limit()方法,並突出它們的相似之處和不同之處。
儘管這兩個操作最初看起來非常相似,但它們實際上表現得非常不同並,且不可互換。實際上,它們是互補的,並且在一起使用時可以很方便。
2. skip()方法
skip方法是一個中間操作,跳過stream中的前n個元素,n不能為負值。如果n大於stream的大小,則返回空stream。
我們來看一個例子:
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.filter(i -> i % 2 == 0)
.skip(2)
.forEach(i -> System.out.print(i + " "));
上面的代碼中,獲取流中的偶數,並跳過前兩個。因此,我們的結果是:
6 8 10
上面的stream在執行的時候,forEach處理每個元素的時候,當到skip()的時候,skip知道前兩項必須被丟棄,因此它們不會將添加到結果流中。之後,它會創建並返回包含其餘項目的流。
為了做到這一點,skip()操作必須保持元素的狀態。出於這個原因,我們說skip()是一個有狀態操作。
3. limit()方法
limt(n)方法是另一種返回不超過請求大小的stream的中間操作。和上面一樣,n參數不能為負數。
我們在一個例子中使用它:
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.filter(i -> i % 2 == 0)
.limit(2)
.forEach(i -> System.out.print(i + " "));
在這種情況下,我們從我們的int流中只獲取兩個偶數:
2 4
與skip()操作一樣,limit()也是一個有狀態操作,因為它必須保持正在處理的項的狀態。
但與skip()消耗整個流不同,只要limit()達到最大項數,它就不再消耗任何項,只返回結果流。因此,我們說limit()是一種短路操作。
使用無限流時,limit()對於將流截斷為有限流非常有用:
Stream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 0)
.limit(10)
.forEach(System.out::println);
在這個例子中,我們將無限的數字流截斷為只有十個偶數的流。
4.結合skip()和limit()
正如我們前面提到的,skip和limit是互補的,如果將它們組合在一起,在某些情況下會非常有用。
想像一下,修改之前的示例,以便以10個為一組獲得偶數。我們可以通過在同一個流上同時使用skip()和limit()來實現:
private static List<Integer> getEvenNumbers(int offset, int limit) {
return Stream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 0)
.skip(offset)
.limit(limit)
.collect(Collectors.toList());
可以使用此方法輕鬆地對流進行分頁。即使這是非常簡單的分頁,也可以看到對stream進行切片操作是多麼強大。
5.結論
在這篇簡短的文章中,我們展示了Java Stream API 的skip()和limit()方法的相同點和不同點。還實現了一些簡單的示例來說明如何使用。
與往常一樣,GitHub上提供了示例的完整原始碼 。
編譯:baeldung java-stream-skip-vs-limit