流式处理
流是一系列数据项,一次只生成一项。程序可以从输 入流中一个一个读取数据项,然后以同样的方式将数据项写入输出流。一个程序的输出流很可能是另一个程序的输入流。
流的特点元素序列——就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。集合讲的是数据,流讲的是计算。
源——流会使用一个提供数据的源,如集合、数组或输入/输出资源。 请注意,从有序集 合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致。数据处理操作——流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中 的常用操作,如filter、map、reduce、find、match、sort等。流操作可以顺序执行,也可并行执行。
流水线——很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大
的流水线。
如:
内部迭代——与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的。这意味着我们不需要去写循环迭代集合了。
同一个流,只能消费一次。
请注意,和迭代器类似,流只能遍历一次。遍历完之后,我们就说这个流已经被消费掉了。 你可以从原始数据源那里再获得一个新的流来重新遍历一遍,就像迭代器一样。例如,以下代码会抛出一个异常,说流已被消费掉了:
java.lang.IllegalStateException:流已被操作 或关闭
Java 8在java.util.stream中添加了一个Stream API;Stream 就是一系列T类型的项目。Stream API的很多方法可以链接起来形成一个复杂的流水线.
最经典的流式API是在集合中。Java 8中的集合支持一个新的 stream方法,它会返回一个java.util.stream.Stream的流。
下面是一个常见的流式风格的Java集合操作。
在本例中,我们先是对menu调用stream方法,由菜单得到一个流。数据源是菜肴列表(菜单),它给流提供一个元素序列。
接下来,对流应用一系列数据处理操作:filter、map、limit 和collect。除了collect之外,所有这些操作都会返回另一个流,这样它们就可以接成一条流水线,于是就可以看作对源的一个查询。
最后,collect操作开始处理流水线,并返回结果。在调用collect之前,没有任何结果产生,实际上根本就没有从menu里选择元素。你可以这么理解:链中的方法调用都在排队等待,直到调用collect。
下面的图说明了这个过程。
本例中,相关的几个函数的简要说明:
filter——接受Lambda,从流中排除某些元素。在本例中,通过传递lambda d -> d.getCalories() > 300,选择出热量超过300卡路里的菜肴。
map——接受一个Lambda,将元素转换成其他形式或提取信息。在本例中,通过传递方法引用Dish::getName,相当于Lambda d -> d.getName(),提取了每道菜的菜名。
limit——截断流,使其元素不超过给定数量。
collect——将流转换为其他形式。在本例中,流被转换为一个列表。
后面会详细写写流的各种api的含义及应用。