5.2 流的切片
本节会讨论如何通过其他方式选择或跳过流中的某些元素。使用Stream的一些操作结合谓词,你可以高效地选择或者丢弃流中的元素,譬如忽略流的前几个元素,或者按照设定的大小对流实施截短操作。
5.2.1 使用谓词对流进行切片
Java 9引入了两个新方法,可以高效地选择流中的元素,这两个方法分别是:takeWhile和dropWhile。
- 使用
takeWhile
假设你需要处理下面这个菜单列表:
List<Dish> specialMenu = Arrays.asList(new Dish("seasonal fruit", true, 120, Dish.Type.OTHER),new Dish("prawns", false, 300, Dish.Type.FISH),new Dish("rice", true, 350, Dish.Type.OTHER),new Dish("chicken", false, 400, Dish.Type.MEAT),new Dish("french fries", true, 530, Dish.Type.OTHER));
怎样才能从这些菜单中选出热量少于320卡路里的那些菜肴呢?你本能地想起了前面章节学习过的filter操作,它可以执行下面的动作:
List<Dish> filteredMenu= specialMenu.stream().filter(dish -> dish.getCalories() < 320).collect(toList()); ←---- 由季节性的水果、虾构成的列表
然而,采用这种方式,初始列表中的元素已经按照热量进行了排序操作!这里采用filter的缺点是,你需要遍历整个流中的数据,对其中的每一个元素执行谓词操作。而你本可以在发现第一个热量大于(或者等于)320卡路里的菜肴时就停止处理的。如果你要处理的列表规模不大,这不算什么大问题,但是,如果你要处理的是一个由海量元素构成的流,采用恰当的方式所带来的性能提升还是很可观的。然而,怎样才能达到期望的效果呢?takeWhile操作就是为此而生的!它可以帮助你利用谓词对流进行分片(即便你要处理的流是无限流也毫无困难)。更妙的是,它会在遭遇第一个不符合要求的元素时停止处理。下面这段代码演示了如何使用takeWhile:
List<Dish> slicedMenu1= specialMenu.stream().takeWhile(dish -> dish.getCalories() < 320).collect(toList()); ←---- 由季节性的水果、虾构成的列表
- 使用
dropWhile
如果你想要的是其他的元素,又该怎么办呢?譬如,你想要找出那些热量大于320卡路里的元素。你可以借助dropWhile操作达到这一目标:
List<Dish> slicedMenu2= specialMenu.stream().dropWhile(dish -> dish.getCalories() < 320).collect(toList()); ←---- 由米饭、鸡肉以及炸薯条构成的列表
dropWhile操作是对takeWhile操作的补充。它会从头开始,丢弃所有谓词结果为false的元素。一旦遭遇谓词计算的结果为true,它就停止处理,并返回所有剩余的元素,即便要处理的对象是一个由无限数量元素构成的流,它也能工作得很好。
5.2.2 截短流
流支持limit(n)方法,该方法会返回另一个不超过给定长度的流。所需的长度作为参数传递给limit。如果流是有序的,则最多会返回前n个元素。比如,你可以建立一个List,选出热量超过300卡路里的头三道菜:
List<Dish> dishes = specialMenu.stream().filter(dish -> dish.getCalories() > 300).limit(3).collect(toList()); ←---- 列出米饭、鸡肉、炸薯条
图5-3展示了filter和limit的组合。你可以看到,该方法只选出了符合谓词的头三个元素,然后就立即返回了结果。

图 5-3 截短流
请注意,limit也可以用在无序流上,比如源是一个Set。这种情况下,limit的结果不会以任何顺序排列。
5.2.3 跳过元素
流还支持skip(n)方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流。请注意,limit(n)和skip(n)是互补的!例如,下面的代码将跳过热量超过300卡路里的头两道菜,并返回剩下的。图5-4展示了这个查询。
List<Dish> dishes = menu.stream().filter(d -> d.getCalories() > 300).skip(2).collect(toList());

图 5-4 在流中跳过元素
