1、由值创建流

可以使用静态方法Stream.of,通过显式值创建一个流。
它可以接受任意数量的参数。
例如,以下代码直接使用Stream . of创建了一个字符串流。
然后,可以将字符串转换为大写,再一个个打印出来:
image.png
可以使用empty得到一个空流,如下所示:
Stream emptyStream = Stream. empty();

2、由数组创建流

可以使用静态方法Arrays . stream从数组创建一个流。
它接受一个数组作为参数。
例如,可以将一个原始类型int的数组转换成一个Intstream,如下所示:
image.png

3、由文件生成流

Java中用于处理文件等I/O操作的NIO API ( 非阻塞I/O) 已更新,以便利用Stream API。
java.nio. file.Files中的很多静态方法都会返回一个流。
例如,一个很有用的方法是Files.lines,它会返回一个由指定文件中的各行构成的字符串流。
可以用这个方法看看一个文件中有多少各不相同的词:
image.png
你可以使用Files.lines得到一个流,其中的每个元素都是给定文件中的一行。
应该注意的是,该如何使用flatMap产生一个扁 平的单词流,而不是给每一行生成一个单词流。

4、由函数生成流:创建无限流

Stream API提供了两个静态方法来从函数生成流: Stream. iterate和Stream. generate。
这两个操作可以创建所谓的无限流,不像从固定集合创建的流那样有固定大小的流。
由iterate和generate产生的流会用给定的函数按需创建值,因此可以无穷无尽地计算下去。
一般来说,应该使用limit (n)来对这种流加以限制,以避免打印无穷多个值。

4.1、迭代

先来看一个iterate的简单例子:
image.png
iterate方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda ( UnaryOperator类型)。
这里,我们使用Lambda n -> n + 2,返回的是前一个元素加上2。
因此,iterate方法生成了一个所有正偶数的流,流的第一个元素是初始值0。
然后加上2来生成新的值2,再加上2来得到新的值4,以此类推。
这种iterate操作基本上是顺序的,因为结果取决于前一次应用。
请注意,此操作将生成一个无限流,这个流没有结尾,因为值是按需计算的,可以永远计算下去。
这个流是无界的,正如前面所讨论的,这是流和集合之间的一个关键区别。
可以使用limit方法来显式限制流的大小,这里只选择了前10个偶数。
然后可以调用forEach终端操作来消费流,并分别打印每个元素。
一般来说,在需要依次生成一系列值的时候应该使用iterate,比如一系列日期: 1月31日,2月1日,依此类推。
image.png
image.png

4.2、生成

与iterate方法类似,generate方法也可按需生成一个无限流。
但generate不是依次 对每个新生成的值应用函数的。
它接受一个Supplier类型的Lambda提供新的值。
先来看一个简单的用法:
image.png
这段代码将生成一个流,其中有五个0到1之间的随机双精度数。
例如,运行一次得到了下面
的结果
image.png
Math.Random静态方法被用作新值生成器。
同样,你可以用limit方法显式限制流的大小, 否则流将会无限长。
generate方法还有什么用途。
这里使用的供应源(指向Math.random的方法引用)是无状态的:它不会在任何地方记录任何值,以备以后计算使用。
但供应源不一定是无状态的。
你可以创建存储状态的供应源,它可以修改状态,并在为流生成下一个值时使用。
举个例子,下面将展示如何利用generate创建测验5.4中的斐波纳契数列,这样可以和iterate方法比较一下。
但很重要的一点是,在并行代码中使用有状态的供应源是不安全的。
在这个例子中会使用IntStream说明避免装箱操作的代码。
IntStream的generate方 法会接受一个IntSupplier,而不是Supplier
例如,可以这样来生成一个全是1的无限流:
IntStream ones = IntStream.generate(() -> 1);
Lambda允许你创建函数式接口的实例,只要直接内联提供方法的实现就可以。
也可以像下面这样,通过实现IntSupplier接口中定义的getAsInt方法显式传递一个对象(虽然这看起来是无缘无故地绕圈子):
image.png
generate方法将使用给定的供应源,并反复调用getAsInt方法,而这个方法总是返回2。
但这里使用的匿名类和Lambda的区别在于,匿名类可以通过字段定义状态,而状态又可以用 getAsInt方法来修改。
这是一个副作用的例子。
迄今见过的所有Lambda都是没有副作用的,它们没有改变任何状态。
回到斐波纳契数列的任务上,现在需要做的是建立一个IntSupplier,它要把前一项的值保存在状态中,以便getAsInt用它来计算下一项。
此外,在下一次调用它的时候,还要更新IntSupplier的状态。
下面的代码就是如何创建一个在调用时返回下一个斐波纳契项的IntSupplier:
image.png
上面的代码创建了一个IntSupplier的实例。
此对象有可变的状态:它在两个实例变量中记录了前一个斐波纳契项和当前的斐波纳契项。
getAsInt在调用时会改变对象的状态,由此在 每次调用时产生新的值。
相比之下,使用iterate的方法则是纯粹不变的:它没有修改现有状态, 但在每次迭代时会创建新的元组。
应该始终采用不变的方法,以便并行处理流,并保持结果正确。
请注意,因为处理的是一个无限流,所以必须使用limit操作来显式限制它的大小;否则,终端操作(这里是forEach)将永远计算下去。
同样,不能对无限流做排序或归约,因为所有元素都需要处理,而这永远也完不成。