1.简介
本文将讨论Java Stream API的skip()和limit()方法,并突出它们的相似之处和不同之处。
尽管这两个操作最初看起来非常相似,但它们实际上表现得非常不同并,且不可互换。实际上,它们是互补的,并且在一起使用时可以很方便。
2. skip()方法
skip方法是一个中间操作,跳过stream中的前n个元素,n不能为负值。如果n大于stream的大小,则返回空stream。
我们来看一个例子:
[java]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 + " "));[/java]
上面的代码中,获取流中的偶数,并跳过前两个。因此,我们的结果是:
[java]6 8 10[/java]
上面的stream在执行的时候,forEach处理每个元素的时候,当到skip()的时候,skip知道前两项必须被丢弃,因此它们不会将添加到结果流中。之后,它会创建并返回包含其余项目的流。
为了做到这一点,skip()操作必须保持元素的状态。出于这个原因,我们说skip()是一个有状态操作。
3. limit()方法
limt(n)方法是另一种返回不超过请求大小的stream的中间操作。和上面一样,n参数不能为负数。
我们在一个例子中使用它:
[java]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 + " "));[/java]
在这种情况下,我们从我们的int流中只获取两个偶数:
[java]2 4[/java]
与skip()操作一样,limit()也是一个有状态操作,因为它必须保持正在处理的项的状态。
但与skip()消耗整个流不同,只要limit()达到最大项数,它就不再消耗任何项,只返回结果流。因此,我们说limit()是一种短路操作。
使用无限流时,limit()对于将流截断为有限流非常有用:
[java]Stream.iterate(0, i -> i + 1) .filter(i -> i % 2 == 0) .limit(10) .forEach(System.out::println);[/java]
在这个例子中,我们将无限的数字流截断为只有十个偶数的流。
4.结合skip()和limit()
正如我们前面提到的,skip和limit是互补的,如果将它们组合在一起,在某些情况下会非常有用。
想象一下,修改之前的示例,以便以10个为一组获得偶数。我们可以通过在同一个流上同时使用skip()和limit()来实现:
[java]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());[/java]
可以使用此方法轻松地对流进行分页。即使这是非常简单的分页,也可以看到对stream进行切片操作是多么强大。
5.结论
在这篇简短的文章中,我们展示了Java Stream API 的skip()和limit()方法的相同点和不同点。还实现了一些简单的示例来说明如何使用。
编译:https://www.baeldung.com/java-stream-skip-vs-limit