- 类型参数:
-
T
- 流元素的类型
- 所有超接口:
-
AutoCloseable
,BaseStream<T,
Stream<T>>
Stream
和 IntStream
进行聚合操作的情况:
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();
在这个示例中,widgets
是一个 Collection<Widget>
。我们通过 Collection.stream()
创建了一个 Widget
对象流,对其进行过滤以生成仅包含红色小部件的流,然后将其转换为表示每个红色小部件重量的 int
值流。然后对这个流进行求和以得到总重量。
除了 Stream
,即对象引用流,还有针对 IntStream
、LongStream
和 DoubleStream
的基本特化流,它们都被称为“流”并符合此处描述的特性和限制。
为了执行计算,流 操作 被组合成一个 流水线。流水线由一个源(可以是数组、集合、生成函数、I/O 通道等)、零个或多个 中间操作(将一个流转换为另一个流,如 filter(Predicate)
)和一个 终端操作(生成结果或副作用,如 count()
或 forEach(Consumer)
)组成。流是惰性的;只有在启动终端操作时才会对源数据进行计算,并且只有在需要时才会消耗源元素。
流实现在优化结果计算方面有很大的自由度。例如,如果流实现可以证明省略操作(或整个阶段)不会影响计算结果,那么它可以自由省略流水线的操作(或整个阶段)-- 因此省略行为参数的调用。这意味着行为参数的副作用可能并不总是被执行,除非另有规定(例如通过终端操作 forEach
和 forEachOrdered
)。 (有关这种优化的具体示例,请参见文档中记录的 count()
操作的 API 注释。有关更多详细信息,请参见流包文档的 副作用 部分。)
集合和流,虽然在表面上有一些相似之处,但目标不同。集合主要关注对其元素的高效管理和访问。相比之下,流不提供直接访问或操作其元素的手段,而是关注描述其源和将在该源上聚合执行的计算操作。但是,如果提供的流操作不提供所需的功能,则可以使用 BaseStream.iterator()
和 BaseStream.spliterator()
操作执行受控遍历。
流水线,就像上面的“小部件”示例一样,可以被视为对流源的一个 查询。除非源明确设计用于并发修改(例如 ConcurrentHashMap
),否则在查询流源时修改流源可能导致不可预测或错误的行为。
大多数流操作接受描述用户指定行为的参数,例如在上面示例中传递给 mapToInt
的 lambda 表达式 w -> w.getWeight()
。为了保持正确的行为,这些 行为参数:
这些参数始终是 函数接口 的实例,例如 Function
,通常是 lambda 表达式或方法引用。除非另有规定,这些参数必须是 非空 的。
应该只对流进行操作(调用中间或终端流操作)一次。例如,“分叉”流,在其中相同的源馈送两个或更多流水线,或对同一流的多次遍历,都是不允许的。如果流实现检测到流被重用,它可能会抛出 IllegalStateException
。但是,由于一些流操作可能返回它们的接收者而不是一个新的流对象,因此可能无法在所有情况下检测到重用。
流具有一个 BaseStream.close()
方法,并实现了 AutoCloseable
。在流关闭后对其进行操作将抛出 IllegalStateException
。大多数流实例实际上在使用后不需要关闭,因为它们由集合、数组或生成函数支持,不需要特殊的资源管理。通常,只有其源是 IO 通道的流,例如由 Files.lines(Path)
返回的流,才需要关闭。如果流确实需要关闭,则必须在 try-with-resources 语句或类似的控制结构中作为资源打开,以确保在其操作完成后及时关闭。
流水线可以顺序执行,也可以以 并行 执行。这种执行模式是流的一个属性。流创建时会选择初始的顺序或并行执行方式。(例如,Collection.stream()
创建一个顺序流,Collection.parallelStream()
创建一个并行流。)这种执行模式的选择可以通过 BaseStream.sequential()
或 BaseStream.parallel()
方法进行修改,并可以通过 BaseStream.isParallel()
方法进行查询。
- 自 JDK 版本:
- 1.8
- 参见:
-
Nested Class Summary
-
Method Summary
Modifier and TypeMethodDescriptionboolean
返回此流的所有元素是否都与提供的断言匹配。boolean
返回此流的任何元素是否与提供的断言匹配。static <T> Stream.Builder
<T> builder()
返回一个Stream
的构建器。<R> R
collect
(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner) 对此流的元素执行一个 可变归约 操作。<R,
A> R 对此流的元素使用Collector
执行一个 可变归约 操作。static <T> Stream
<T> 创建一个延迟连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。long
count()
返回此流中元素的计数。distinct()
返回此流的不同元素(根据Object.equals(Object)
)组成的流。返回,如果此流是有序的,则在删除与给定断言匹配的元素的最长前缀后,由剩余元素组成的流。static <T> Stream
<T> empty()
返回一个空的顺序Stream
。返回由与给定断言匹配的此流的元素组成的流。findAny()
返回一个描述流中某个元素的Optional
,如果流为空则返回一个空的Optional
。返回描述此流的第一个元素的Optional
,如果流为空则返回一个空的Optional
。<R> Stream
<R> 返回由将此流的每个元素替换为应用提供的映射函数到每个元素产生的映射流的内容组成的流。flatMapToDouble
(Function<? super T, ? extends DoubleStream> mapper) 返回由将此流的每个元素替换为应用提供的映射函数到每个元素产生的映射流的内容组成的DoubleStream
。flatMapToInt
(Function<? super T, ? extends IntStream> mapper) 返回由将此流的每个元素替换为应用提供的映射函数到每个元素产生的映射流的内容组成的IntStream
。flatMapToLong
(Function<? super T, ? extends LongStream> mapper) 返回由将此流的每个元素替换为应用提供的映射函数到每个元素产生的映射流的内容组成的LongStream
。void
对此流的每个元素执行一个操作。void
forEachOrdered
(Consumer<? super T> action) 如果流具有定义的遭遇顺序,则对此流的每个元素按照流的遭遇顺序执行一个操作。static <T> Stream
<T> 返回一个无限顺序无序流,其中每个元素由提供的Supplier
生成。static <T> Stream
<T> iterate
(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) 返回一个顺序有序的Stream
,通过对初始元素进行迭代应用给定的next
函数生成,条件是满足给定的hasNext
谓词。static <T> Stream
<T> iterate
(T seed, UnaryOperator<T> f) 返回一个无限顺序有序的Stream
,通过将函数f
应用于初始元素seed
进行迭代生成,生成由seed
,f(seed)
,f(f(seed))
等组成的Stream
。limit
(long maxSize) 返回由此流的元素组成的流,截断长度不超过maxSize
。<R> Stream
<R> 返回由将给定函数应用于此流的元素的结果组成的流。default <R> Stream
<R> mapMulti
(BiConsumer<? super T, ? super Consumer<R>> mapper) 返回由将此流的每个元素替换为多个元素(具体为零个或多个元素)的结果组成的流。default DoubleStream
mapMultiToDouble
(BiConsumer<? super T, ? super DoubleConsumer> mapper) 返回由将此流的每个元素替换为多个元素(具体为零个或多个元素)的结果组成的DoubleStream
。default IntStream
mapMultiToInt
(BiConsumer<? super T, ? super IntConsumer> mapper) 返回由将此流的每个元素替换为多个元素(具体为零个或多个元素)的结果组成的IntStream
。default LongStream
mapMultiToLong
(BiConsumer<? super T, ? super LongConsumer> mapper) 返回由将此流的每个元素替换为多个元素(具体为零个或多个元素)的结果组成的LongStream
。mapToDouble
(ToDoubleFunction<? super T> mapper) 返回由将给定函数应用于此流的元素的结果组成的DoubleStream
。mapToInt
(ToIntFunction<? super T> mapper) 返回由将给定函数应用于此流的元素的结果组成的IntStream
。mapToLong
(ToLongFunction<? super T> mapper) 返回由将给定函数应用于此流的元素的结果组成的LongStream
。max
(Comparator<? super T> comparator) 根据提供的Comparator
返回此流的最大元素。min
(Comparator<? super T> comparator) 根据提供的Comparator
返回此流的最小元素。boolean
返回此流的元素是否没有一个与提供的谓词匹配。static <T> Stream
<T> of
(T t) 返回包含单个元素的顺序Stream
。static <T> Stream
<T> of
(T... values) 返回元素为指定值的顺序有序流。static <T> Stream
<T> ofNullable
(T t) 返回包含单个元素的顺序Stream
,如果非空,则返回一个空的Stream
。返回由此流的元素组成的流,同时在从生成的流中消耗元素时对每个元素执行提供的操作。reduce
(BinaryOperator<T> accumulator) 对此流的元素执行reduction,使用关联累积函数,并返回描述减少值(如果有)的Optional
。reduce
(T identity, BinaryOperator<T> accumulator) 对此流的元素执行reduction,使用提供的身份值和关联累积函数,并返回减少值。<U> U
reduce
(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) 对此流的元素执行reduction,使用提供的身份、累积和组合函数。skip
(long n) 返回丢弃流的前n
个元素后剩余元素组成的流。sorted()
返回根据自然顺序排序的此流的元素组成的流。sorted
(Comparator<? super T> comparator) 返回根据提供的Comparator
排序的此流的元素组成的流。如果此流有序,则返回由从此流中获取的满足给定谓词的元素组成的最长前缀的流。Object[]
toArray()
返回包含此流的元素的数组。<A> A[]
toArray
(IntFunction<A[]> generator) 返回包含此流的元素的数组,使用提供的generator
函数来分配返回的数组,以及可能需要用于分区执行或调整大小的其他数组。toList()
将此流的元素累积为List
。Methods declared in interface java.util.stream.BaseStream
close, isParallel, iterator, onClose, parallel, sequential, spliterator, unordered
-
Method Details
-
filter
返回由与给定谓词匹配的此流的元素组成的流。这是一个中间操作。
-
map
返回由将给定函数应用于此流的元素的结果组成的流。这是一个中间操作。
-
mapToInt
返回由将给定函数应用于此流的元素的结果组成的IntStream
。这是一个中间操作。
-
mapToLong
返回由将给定函数应用于此流的元素的结果组成的LongStream
。这是一个中间操作。
-
mapToDouble
返回由将给定函数应用于此流的元素的结果组成的DoubleStream
。这是一个中间操作。
-
flatMap
- API注释:
-
flatMap()
操作的效果是对流的元素应用一对多转换,然后将结果元素展平为新流。示例。
如果
orders
是购买订单的流,每个购买订单包含一组行项目,则以下代码会生成一个包含所有订单中所有行项目的流:orders.flatMap(order -> order.getLineItems().stream())...
如果
path
是文件的路径,则以下代码会生成该文件中包含的words
的流:
传递给Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8); Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
flatMap
的mapper
函数使用简单的正则表达式将一行拆分为单词数组,然后从该数组创建单词流。 - 类型参数:
-
R
- 新流的元素类型 - 参数:
-
mapper
- 一个非干扰、无状态的函数,应用于每个元素,产生新值的流 - 返回:
- 新流
- 参见:
-
flatMapToInt
-
flatMapToLong
-
flatMapToDouble
-
mapMulti
返回一个流,其中包含将此流的每个元素替换为多个元素的结果,具体为零个或多个元素。替换是通过将提供的映射函数应用于每个元素,并与接受替换元素的consumer参数一起执行。映射函数调用消费者零次或多次以提供替换元素。这是一个中间操作。
如果consumer参数在其应用于映射函数的范围之外使用,则结果是未定义的。
- API注释:
-
此方法类似于
flatMap
,因为它将一对多的转换应用于流的元素,并将结果元素展平为新流。在以下情况下,此方法优于flatMap
:- 当用一个小(可能为零)数量的元素替换每个流元素时。使用此方法避免了为每组结果元素创建新的Stream实例的开销,这是
flatMap
所需的。 - 当更容易使用命令式方法生成结果元素,而不是以Stream的形式返回它们时。
如果将lambda表达式作为映射函数参数提供,则可能需要额外的类型信息以正确推断返回流的元素类型
<R>
。这可以通过为lambda参数提供显式类型声明或作为mapMulti
调用的显式类型参数来提供。示例
给定一个
Number
对象流,以下代码生成仅包含Integer
对象的列表:Stream<Number> numbers = ... ; List<Integer> integers = numbers.<Integer>mapMulti((number, consumer) -> { if (number instanceof Integer i) consumer.accept(i); }) .collect(Collectors.toList());
如果我们有一个
Iterable<Object>
并且需要递归展开其元素,这些元素本身是Iterable
类型,我们可以使用mapMulti
如下:class C { static void expandIterable(Object e, Consumer<Object> c) { if (e instanceof Iterable<?> elements) { for (Object ie : elements) { expandIterable(ie, c); } } else if (e != null) { c.accept(e); } } public static void main(String[] args) { var nestedList = List.of(1, List.of(2, List.of(3, 4)), 5); Stream<Object> expandedStream = nestedList.stream().mapMulti(C::expandIterable); } }
- 当用一个小(可能为零)数量的元素替换每个流元素时。使用此方法避免了为每组结果元素创建新的Stream实例的开销,这是
- 实现要求:
-
默认实现在此流上调用
flatMap
,传递一个行为如下的函数。首先,它使用一个Consumer
调用映射函数,该函数将替换元素累积到新创建的内部缓冲区中。当映射函数返回时,它从内部缓冲区创建一个流。最后,它将此流返回给flatMap
。 - 类型参数:
-
R
- 新流的元素类型 - 参数:
-
mapper
- 一个非干扰、无状态的函数,生成替换元素 - 返回:
- 新流
- 自版本:
- 16
- 参见:
-
mapMultiToInt
-
mapMultiToLong
-
mapMultiToDouble
-
distinct
返回一个流,其中包含此流的不同元素(根据Object.equals(Object)
)。对于有序流,选择不同元素是稳定的(对于重复元素,保留首次出现的元素)。对于无序流,不保证稳定性。
这是一个有状态的中间操作。
- API 注意:
-
在并行流管道中保持
distinct()
的稳定性相对昂贵(需要操作作为完全屏障,具有大量缓冲开销),通常不需要稳定性。使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
去除排序约束可能会在并行流管道中显著提高distinct()
的执行效率,如果您的情况允许的话。如果需要与遇到顺序一致,并且在并行流管道中使用distinct()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
进行顺序执行可能会提高性能。 - 返回:
- 新流
-
sorted
返回一个流,其中包含此流的元素,按自然顺序排序。如果此流的元素不是Comparable
,则在执行终端操作时可能会抛出java.lang.ClassCastException
。对于有序流,排序是稳定的。对于无序流,不保证稳定性。
这是一个有状态的中间操作。
- 返回:
- 新流
-
sorted
-
peek
返回一个流,其中包含此流的元素,并在从生成的流中消耗元素时对每个元素执行提供的操作。这是一个中间操作。
对于并行流管道,操作可能在上游操作使元素在任何时间和任何线程中可用时调用。如果操作修改共享状态,则负责提供所需的同步。
- API 注意:
-
此方法主要用于支持调试,您可以在流中的某个特定点看到元素的流动:
Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList());
在流实现能够优化掉一些或所有元素的生成(例如使用
findFirst
等短路操作,或在count()
中描述的示例中),对于这些元素不会调用操作。 - 参数:
-
action
- 在从流中消耗元素时执行的非干扰操作 - 返回:
- 新流
-
limit
返回一个流,其中包含此流的元素,截断长度不超过maxSize
。这是一个短路有状态的中间操作。
- API 注意:
-
虽然
limit()
在顺序流管道上通常是廉价的操作,但在有序并行管道上可能会非常昂贵,特别是对于较大的maxSize
值,因为limit(n)
受限于返回不仅仅是任意的n元素,而是遵循遇到顺序的n元素。使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
去除排序约束可能会在并行管道中显著加快limit()
的速度,如果您的情况允许的话。如果需要与遇到顺序一致,并且在并行管道中使用limit()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
进行顺序执行可能会提高性能。 - 参数:
-
maxSize
- 流应限制的元素数量 - 返回:
- 新流
- 抛出:
-
IllegalArgumentException
- 如果maxSize
为负数
-
skip
- API 注意:
-
虽然
skip()
在顺序流管道上通常是廉价的操作,但在有序并行管道上可能会非常昂贵,特别是对于较大的n
值,因为skip(n)
受限于跳过不仅仅是任意的n元素,而是遵循遇到顺序的n元素。使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
去除排序约束可能会在并行管道中显著加快skip()
的速度,如果您的情况允许的话。如果需要与遇到顺序一致,并且在并行管道中使用skip()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
进行顺序执行可能会提高性能。 - 参数:
-
n
- 要跳过的前导元素数量 - 返回:
- 新流
- 抛出:
-
IllegalArgumentException
- 如果n
为负数
-
takeWhile
如果此流有序,则返回一个流,其中包含从此流中获取的与给定谓词匹配的元素的最长前缀。否则,如果此流是无序的,则返回一个流,其中包含从此流中获取的与给定谓词匹配的元素的子集。如果此流有序,则最长前缀是与给定谓词匹配的此流的元素的连续序列。序列的第一个元素是此流的第一个元素,紧随序列最后一个元素的元素不匹配给定谓词。
如果此流是无序的,并且此流的一些(但不是全部)元素与给定谓词匹配,则此操作的行为是不确定的;它可以获取匹配元素的任何子集(包括空集)。
无论此流是有序还是无序,如果此流的所有元素都与给定谓词匹配,则此操作获取所有元素(结果与输入相同),或者如果流的没有元素与给定谓词匹配,则不获取任何元素(结果是空流)。
这是一个短路有状态的中间操作。
- API 注意:
-
虽然
takeWhile()
在顺序流管道上通常是廉价的操作,但在有序并行管道上可能会非常昂贵,因为该操作受限于返回遇到顺序中元素的最长前缀,而不仅仅是任何有效前缀。使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
去除排序约束可能会在并行管道中显著加快takeWhile()
的速度,如果您的情况允许的话。如果需要与遇到顺序一致,并且在并行管道中使用takeWhile()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
进行顺序执行可能会提高性能。 - 实现要求:
-
默认实现获取此流的
spliterator
,包装该spliterator以支持此操作在遍历时的语义,并返回与包装的spliterator关联的新流。返回的流保留此流的执行特性(即根据BaseStream.isParallel()
的并行或顺序执行),但包装的spliterator可能选择不支持拆分。当关闭返回的流时,将调用返回流和此流的关闭处理程序。 - 参数:
-
predicate
- 应用于元素以确定元素的最长前缀的非干扰、无状态谓词 - 返回:
- 新流
- 自:
- 9
-
dropWhile
返回,如果此流是有序的,则返回一个流,该流由匹配给定谓词的元素的最长前缀之后剩余的元素组成。否则,如果此流是无序的,则返回一个流,该流由匹配给定谓词的元素的子集之后剩余的元素组成。如果此流是有序的,则最长前缀是此流的元素的连续序列,这些元素与给定谓词匹配。序列的第一个元素是此流的第一个元素,紧随序列最后一个元素的元素不匹配给定谓词。
如果此流是无序的,并且此流的一些(但不是全部)元素与给定谓词匹配,则此操作的行为是不确定的;它可以自由地丢弃任何匹配元素的子集(包括空集)。
无论此流是有序还是无序,如果此流的所有元素都与给定谓词匹配,则此操作会丢弃所有元素(结果是空流),或者如果流的没有元素与给定谓词匹配,则不会丢弃任何元素(结果与输入相同)。
这是一个有状态的中间操作。
- API 注意:
-
虽然
dropWhile()
在顺序流管道上通常是一项廉价操作,但在有序并行管道上可能会非常昂贵,因为该操作受限于返回不仅是任何有效前缀,而是遵守遇到顺序的元素的最长前缀。使用无序流源(例如generate(Supplier)
)或通过BaseStream.unordered()
去除排序约束可能会显著加快并行管道中dropWhile()
的速度,如果您的情况允许的话。如果需要与遇到顺序一致,并且在并行管道中使用dropWhile()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
可以改善性能。 - 实现要求:
-
默认实现获取此流的
spliterator
,包装该spliterator以支持此操作在遍历时的语义,并返回与包装的spliterator关联的新流。返回的流保留此流的执行特性(即根据BaseStream.isParallel()
的并行或顺序执行),但包装的spliterator可能选择不支持拆分。当关闭返回的流时,将调用返回流和此流的关闭处理程序。 - 参数:
-
predicate
- 一个非干扰、无状态的谓词,用于确定元素的最长前缀。 - 返回:
- 新流
- 自版本:
- 9
-
forEach
对此流的每个元素执行操作。这是一个终端操作。
此操作的行为明确是不确定的。对于并行流管道,此操作不保证遵守流的遇到顺序,因为这样做将牺牲并行性的好处。对于任何给定元素,操作可能在库选择的任何时间和任何线程中执行。如果操作访问共享状态,则负责提供所需的同步。
- 参数:
-
action
- 一个非干扰操作,对元素执行操作
-
forEachOrdered
对此流的每个元素按照流的遇到顺序执行操作,如果流具有定义的遇到顺序。这是一个终端操作。
此操作逐个处理元素,如果存在遇到顺序,则按照遇到顺序执行。对于一个元素执行操作发生在对后续元素执行操作之前,但对于任何给定元素,操作可能在库选择的任何线程中执行。
- 参数:
-
action
- 一个非干扰操作,对元素执行操作 - 参见:
-
toArray
Object[] toArray()返回包含此流元素的数组。这是一个终端操作。
- 返回:
-
一个数组,其运行时组件类型为
Object
,包含此流的元素
-
toArray
返回包含此流元素的数组,使用提供的generator
函数来分配返回的数组,以及可能需要用于分区执行或调整大小的任何其他数组。这是一个终端操作。
- API 注意:
-
生成器函数接受一个整数,即所需数组的大小,并生成所需大小的数组。这可以用数组构造函数引用简洁地表示为:
Person[] men = people.stream() .filter(p -> p.getGender() == MALE) .toArray(Person[]::new);
- 类型参数:
-
A
- 结果数组的组件类型 - 参数:
-
generator
- 一个函数,产生所需类型和提供长度的新数组 - 返回:
- 包含此流中元素的数组
- 抛出:
-
ArrayStoreException
- 如果此流的任何元素的运行时类型不可分配给生成的数组的运行时组件类型
-
reduce
-
reduce
对此流的元素执行一个关联累积函数的归约,并返回描述归约值的Optional
,如果有的话。这等效于:
但不受限于顺序执行。boolean foundAny = false; T result = null; for (T element : this stream) { if (!foundAny) { foundAny = true; result = element; } else result = accumulator.apply(result, element); } return foundAny ? Optional.of(result) : Optional.empty();
累加函数必须是一个关联函数。
这是一个终端操作。
- 参数:
-
accumulator
- 一个关联、非干扰、无状态的函数,用于组合两个值 - 返回:
-
一个描述归约值的
Optional
- 抛出:
-
NullPointerException
- 如果归约的结果为null - 参见:
-
reduce
执行对此流的元素进行减少,使用提供的标识、累积和组合函数。这相当于:
但不受顺序执行的限制。U result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
identity
值必须是组合函数的标识。这意味着对于所有u
,combiner(identity, u)
等于u
。此外,combiner
函数必须与accumulator
函数兼容;对于所有u
和t
,必须满足以下条件:combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
这是一个终端操作。
-
collect
对此流的元素执行可变减少操作。可变减少是指减少值是可变结果容器,例如ArrayList
,元素通过更新结果的状态而不是替换结果来合并。这会产生等效于:R result = supplier.get(); for (T element : this stream) accumulator.accept(result, element); return result;
与
reduce(Object, BinaryOperator)
类似,collect
操作可以并行化,而无需额外的同步。这是一个终端操作。
- API 注意:
-
JDK中有许多现有类的签名非常适合用作方法引用作为
collect()
的参数。例如,以下代码将字符串累积到ArrayList
中:List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
以下代码将获取字符串流并将它们连接成单个字符串:
String concat = stringStream.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString();
- 类型参数:
-
R
- 可变结果容器的类型 - 参数:
-
supplier
- 创建新的可变结果容器的函数。对于并行执行,可能会多次调用此函数,并且每次必须返回一个新值。 -
accumulator
- 一个关联、非干扰、无状态的函数,必须将一个元素折叠到结果容器中。 -
combiner
- 一个关联、非干扰、无状态的函数,接受两个部分结果容器并合并它们,必须与累加器函数兼容。组合函数必须将第二个结果容器中的元素折叠到第一个结果容器中。 - 返回:
- 减少的结果
-
collect
使用Collector
在此流的元素上执行可变减少操作。Collector
封装了作为参数传递给collect(Supplier, BiConsumer, BiConsumer)
的函数,允许重用收集策略和组合收集操作,例如多级分组或分区。如果流是并行的,并且
Collector
是concurrent
,并且流是无序的或收集器是unordered
,那么将执行并发减少(有关并发减少的详细信息,请参见Collector
)。这是一个终端操作。
在并行执行时,可能会实例化、填充和合并多个中间结果,以保持可变数据结构的隔离。因此,即使在与非线程安全数据结构(例如
ArrayList
)并行执行时,也不需要额外的同步来进行并行减少。- API 注意:
-
以下代码将字符串累积到列表中:
List<String> asList = stringStream.collect(Collectors.toList());
以下代码将按城市对
Person
对象进行分类:Map<String, List<Person>> peopleByCity = personStream.collect(Collectors.groupingBy(Person::getCity));
以下代码将按州和城市对
Person
对象进行分类,将两个Collector
级联在一起:Map<String, Map<String, List<Person>>> peopleByStateAndCity = personStream.collect(Collectors.groupingBy(Person::getState, Collectors.groupingBy(Person::getCity)));
- 类型参数:
-
R
- 结果的类型 -
A
-Collector
的中间累积类型 - 参数:
-
collector
- 描述减少的Collector
- 返回:
- 减少的结果
- 参见:
-
toList
将此流的元素累积到List
中。列表中的元素将按照此流的遭遇顺序排列(如果存在)。返回的列表是不可修改的;对任何修改器方法的调用将始终导致抛出UnsupportedOperationException
。对返回的列表的实现类型或可序列化性没有保证。返回的实例可能是基于值的。调用者不应对返回实例的标识做任何假设。对这些实例进行的标识敏感操作(引用相等性(
==
)、标识哈希码和同步)是不可靠的,应该避免。这是一个终端操作。
- API 注意:
-
如果需要对返回的对象有更多控制,请使用
Collectors.toCollection(Supplier)
。 - 实现要求:
-
此接口中的实现返回一个List,其产生方式如下:
Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
- 实现说明:
- 大多数Stream实例将重写此方法并提供一个与此接口中的实现相比高度优化的实现。
- 返回:
- 包含流元素的List
- 自:
- 16
-
min
- 参数:
-
comparator
- 用于比较此流的元素的非干扰、无状态Comparator
- 返回:
-
描述此流的最小元素的
Optional
,如果流为空则为空Optional
- 抛出:
-
NullPointerException
- 如果最小元素为null
-
max
- 参数:
-
comparator
- 用于比较此流的元素的非干扰、无状态Comparator
- 返回值:
-
描述此流的最大元素的
Optional
,如果流为空则返回一个空的Optional
- 抛出:
-
NullPointerException
- 如果最大元素为null
-
count
long count()- API 注意:
-
如果能够直接从流源计算计数,实现可以选择不执行流管道(顺序或并行)。在这种情况下,不会遍历任何源元素,也不会评估任何中间操作。强烈不建议具有副作用的行为参数,除了像调试这样的无害情况。例如,考虑以下流:
流源,即List<String> l = Arrays.asList("A", "B", "C", "D"); long count = l.stream().peek(System.out::println).count();
List
的元素数量是已知的,中间操作peek
不会向流注入或移除元素(这可能是flatMap
或filter
操作的情况)。因此,计数是List
的大小,不需要执行流管道,并且作为副作用打印出列表元素。 - 返回值:
- 此流中元素的计数
-
anyMatch
返回此流中是否有任何元素与提供的谓词匹配。如果不需要确定结果,则可能不会对所有元素评估谓词。如果流为空,则返回false
,并且不会评估谓词。这是一个短路终端操作。
-
allMatch
返回此流中是否所有元素都与提供的谓词匹配。如果不需要确定结果,则可能不会对所有元素评估谓词。如果流为空,则返回true
,并且不会评估谓词。这是一个短路终端操作。
-
noneMatch
返回此流中是否没有任何元素与提供的谓词匹配。如果不需要确定结果,则可能不会对所有元素评估谓词。如果流为空,则返回true
,并且不会评估谓词。这是一个短路终端操作。
-
findFirst
- 返回值:
-
描述此流的第一个元素的
Optional
,如果流为空则返回一个空的Optional
- 抛出:
-
NullPointerException
- 如果所选元素为null
-
findAny
返回描述此流的某个元素的Optional
,如果流为空则返回一个空的Optional
。这是一个短路终端操作。
此操作的行为明确是不确定的;它可以自由选择流中的任何元素。这样做是为了在并行操作中获得最大性能;代价是对相同源的多次调用可能不会返回相同的结果。(如果需要稳定的结果,请改用
findFirst()
。)- 返回值:
-
描述此流的某个元素的
Optional
,如果流为空则返回一个空的Optional
- 抛出:
-
NullPointerException
- 如果所选元素为null - 参见:
-
builder
返回Stream
的构建器。- 类型参数:
-
T
- 元素的类型 - 返回值:
- 一个流构建器
-
empty
返回一个空的顺序Stream
。- 类型参数:
-
T
- 流元素的类型 - 返回值:
- 一个空的顺序流
-
of
返回包含单个元素的顺序Stream
。- 类型参数:
-
T
- 流元素的类型 - 参数:
-
t
- 单个元素 - 返回值:
- 一个单例顺序流
-
ofNullable
返回包含单个元素的顺序Stream
,如果非空则返回一个空的Stream
。- 类型参数:
-
T
- 流元素的类型 - 参数:
-
t
- 单个元素 - 返回值:
- 如果指定元素非空,则返回包含单个元素的流,否则返回一个空流
- 自 JDK 9 起:
- 9
-
of
返回其元素为指定值的顺序有限流。- 类型参数:
-
T
- 流元素的类型 - 参数:
-
values
- 新流的元素 - 返回值:
- 新流
-
iterate
返回通过将函数f
迭代应用于初始元素seed
而生成的无限顺序有限Stream
,生成由seed
、f(seed)
、f(f(seed))
等组成的Stream
。Stream.iterate
应该产生与相应for循环产生的相同元素序列:for (T index=seed; hasNext.test(index); index = next.apply(index)) { ... }
如果
hasNext
谓词在种子值上不成立,则生成的序列可能为空。否则,第一个元素将是提供的seed
值,下一个元素(如果存在)将是将next
函数应用于seed
值的结果,依此类推,直到hasNext
谓词指示应终止流的情况。将
hasNext
谓词应用于元素的操作在应用next
函数之前发生。对于给定元素,应用next
函数的操作在应用hasNext
谓词之前发生。对于给定元素,操作可以在库选择的任何线程中执行。- 类型参数:
-
T
- 流元素的类型 - 参数:
-
seed
- 初始元素 -
f
- 应用于前一个元素以生成新元素的函数 - 返回值:
-
新的顺序
Stream
-
iterate
返回通过将给定的next
函数迭代应用于初始元素而生成的顺序有限Stream
,条件是满足给定的hasNext
谓词。一旦hasNext
谓词返回false,流将终止。Stream.iterate
应该产生与相应for循环产生的相同元素序列:for (T index=seed; hasNext.test(index); index = next.apply(index)) { ... }
如果
hasNext
谓词在种子值上不成立,则生成的序列可能为空。否则,第一个元素将是提供的seed
值,下一个元素(如果存在)将是将next
函数应用于seed
值的结果,依此类推,直到hasNext
谓词指示应终止流的情况。将
hasNext
谓词应用于元素的操作在应用next
函数之前发生。对于给定元素,应用next
函数的操作在应用hasNext
谓词之前发生。对于给定元素,操作可以在库选择的任何线程中执行。- 类型参数:
-
T
- 流元素的类型 - 参数:
-
seed
- 初始元素 -
hasNext
- 应用于元素的断言,以确定流何时终止。 -
next
- 应用于前一个元素以生成新元素的函数 - 返回:
-
一个新的顺序
Stream
- 自 JDK 版本:
- 9
-
generate
返回一个无限顺序无序流,其中每个元素由提供的Supplier
生成。这适用于生成常量流、随机元素流等。- 类型参数:
-
T
- 流元素的类型 - 参数:
-
s
- 生成元素的Supplier
- 返回:
-
一个新的无限顺序无序
Stream
-
concat
创建一个惰性连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。如果两个输入流都是有序的,则生成的流是有序的;如果两个输入流中有一个是并行的,则生成的流是并行的。当关闭生成的流时,会调用两个输入流的关闭处理程序。此方法操作两个输入流,并将每个流绑定到其源。因此,对输入流源的后续修改可能不会反映在连接的流结果中。
- API 注释:
-
为了保留优化机会,此方法将每个流绑定到其源,并仅接受两个流作为参数。例如,如果已知每个输入流源的确切大小,则可以计算连接流源的确切大小。要连接更多流而不绑定,或者避免嵌套调用此方法,请尝试创建流的流,并使用恒等函数进行扁平映射,例如:
Stream<T> concat = Stream.of(s1, s2, s3, s4).flatMap(s -> s);
- 实现注释:
-
在构建重复连接的流时要小心。访问深度连接流的元素可能导致深度调用链,甚至
StackOverflowError
。不能保证将对返回的流的顺序/并行执行模式的后续更改传播到输入流。
- 类型参数:
-
T
- 流元素的类型 - 参数:
-
a
- 第一个流 -
b
- 第二个流 - 返回:
- 两个输入流的连接
-