- 类型参数:
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
的原始特化,所有这些都称为“流”并符合此处描述的特征和限制。
为了执行计算,流 操作 被组合成一个 stream pipeline 。流管道由源(可能是数组、集合、生成器函数、I/O 通道等)、零个或多个 intermediate operations(将一个流转换为另一个流,例如 filter(Predicate)
)和一个terminal operation(产生结果或副作用,例如 count()
或 forEach(Consumer)
)。流是懒惰的;仅在启动终端操作时才对源数据进行计算,并且仅在需要时使用源元素。
允许流实现在优化结果计算方面有很大的自由度。例如,流实现可以自由地从流管道中省略操作(或整个阶段)——因此省略行为参数的调用——如果它可以证明它不会影响计算结果。这意味着行为参数的副作用可能并不总是被执行并且不应被依赖,除非另有说明(例如通过终端操作 forEach
和 forEachOrdered
)。 (有关此类优化的具体示例,请参阅记录在 count()
操作上的 API 说明。有关更多详细信息,请参阅流包文档的 副作用 部分。)
集合和流虽然具有一些表面上的相似性,但具有不同的目标。集合主要关注对其元素的有效管理和访问。相比之下,流不提供直接访问或操作其元素的方法,而是关注以声明方式描述其源以及将在该源上聚合执行的计算操作。但是,如果提供的流操作不提供所需的功能,BaseStream.iterator()
和 BaseStream.spliterator()
操作可用于执行受控遍历。
流管道,如上面的“小部件”示例,可以被视为流源上的 query。除非源明确设计用于并发修改(例如 ConcurrentHashMap
),否则在查询流源时修改流源可能会导致不可预测或错误的行为。
大多数流操作接受描述用户指定行为的参数,例如上例中传递给 mapToInt
的 lambda 表达式 w -> w.getWeight()
。为了保持正确的行为,这些 behavioral parameters :
此类参数始终是 功能接口 的实例,例如 Function
,并且通常是 lambda 表达式或方法引用。除非另有说明,否则这些参数必须是 non-null。
流应该只被操作一次(调用中间或终端流操作)。这排除了,例如,“分叉”流,其中相同的源提供两个或多个管道,或同一流的多次遍历。如果流实现检测到流被重用,它可能会抛出 IllegalStateException
。但是,由于某些流操作可能会返回它们的接收器而不是新的流对象,因此可能无法在所有情况下检测到重用。
流有一个 BaseStream.close()
方法并实现 AutoCloseable
。在流关闭后对其进行操作将抛出 IllegalStateException
。大多数流实例在使用后实际上不需要关闭,因为它们由集合、数组或生成函数支持,不需要特殊的资源管理。通常,只有源为 IO 通道的流(例如 Files.lines(Path)
返回的流)才需要关闭。如果流确实需要关闭,则必须在 try-with-resources 语句或类似的控制结构中将其作为资源打开,以确保在其操作完成后立即将其关闭。
流管道可以按顺序执行或在 parallel 中执行。这种执行模式是流的一个属性。流是在最初选择顺序执行或并行执行的情况下创建的。 (例如,Collection.stream()
创建一个顺序流,Collection.parallelStream()
创建一个并行流。)这种执行模式的选择可以通过 BaseStream.sequential()
或 BaseStream.parallel()
方法进行修改,并且可以使用 BaseStream.isParallel()
方法进行查询。
- 自从:
- 1.8
- 参见:
-
内部类总结
内部类 -
方法总结
修饰符和类型方法描述boolean
返回此流的所有元素是否与提供的谓词匹配。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) 返回由给定的next
函数迭代应用到初始元素而产生的顺序有序的Stream
,条件是满足给定的hasNext
谓词。static <T> Stream<T>
iterate
(T seed, UnaryOperator<T> f) 返回由函数f
迭代应用到初始元素seed
产生的无限顺序有序Stream
,产生由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) reduce
(T identity, BinaryOperator<T> accumulator) <U> U
reduce
(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) 使用提供的标识、累积和组合函数对此流的元素执行 减少。skip
(long n) 在丢弃流的前n
个元素后,返回由该流的剩余元素组成的流。sorted()
返回一个流,该流由该流的元素组成,并按自然顺序排序。sorted
(Comparator<? super T> comparator) 返回由该流的元素组成的流,根据提供的Comparator
排序。如果此流是有序的,则返回一个流,该流由从此流中获取的与给定谓词匹配的元素的最长前缀组成。Object[]
toArray()
返回包含此流的元素的数组。<A> A[]
toArray
(IntFunction<A[]> generator) 返回一个包含此流元素的数组,使用提供的generator
函数分配返回的数组,以及分区执行或调整大小可能需要的任何其他数组。toList()
将此流的元素累积到List
中。在接口 java.util.stream.BaseStream 中声明的方法
close, isParallel, iterator, onClose, parallel, sequential, spliterator, unordered
-
方法详情
-
filter
返回一个流,该流由与给定谓词匹配的此流的元素组成。这是一个 中间操作 。
-
map
返回一个流,该流由将给定函数应用于此流的元素的结果组成。这是一个 中间操作 。
-
mapToInt
返回一个IntStream
,由将给定函数应用于此流的元素的结果组成。这是一个 中间操作 。
-
mapToLong
返回一个LongStream
,由将给定函数应用于此流的元素的结果组成。这是一个 中间操作 。
-
mapToDouble
返回一个DoubleStream
,由将给定函数应用于此流的元素的结果组成。这是一个 中间操作 。
-
flatMap
返回一个流,该流由将此流的每个元素替换为通过将提供的映射函数应用于每个元素而生成的映射流的内容组成的结果。每个映射流在其内容被放入该流后都是closed
。 (如果map流是null
,则使用空流。)这是一个 中间操作 。
- 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
所要求的那样。 - 当使用命令式方法生成结果元素比以流的形式返回它们更容易时。
如果提供 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
返回一个IntStream
,由用多个元素(特别是零个或多个元素)替换此流的每个元素的结果组成。通过将提供的映射函数与接受替换元素的consumer参数一起应用于每个元素来执行替换。映射函数零次或多次调用消费者以提供替换元素。这是一个 中间操作 。
如果 consumer 参数在其映射函数的应用范围之外使用,则结果未定义。
- 实现要求:
-
默认实现在此流上调用
flatMapToInt
,传递一个行为如下的函数。首先,它使用IntConsumer
调用映射器函数,将替换元素累积到新创建的内部缓冲区中。当映射器函数返回时,它会从内部缓冲区创建一个IntStream
。最后,它将这个流返回给flatMapToInt
。 - 参数:
mapper
- 生成替换元素的 不干扰、无国籍的 函数- 返回:
- 新流
- 自从:
- 16
- 参见:
-
mapMultiToLong
返回一个LongStream
,由用多个元素(特别是零个或多个元素)替换此流的每个元素的结果组成。通过将提供的映射函数与接受替换元素的consumer参数一起应用于每个元素来执行替换。映射函数零次或多次调用消费者以提供替换元素。这是一个 中间操作 。
如果 consumer 参数在其映射函数的应用范围之外使用,则结果未定义。
- 实现要求:
-
默认实现在此流上调用
flatMapToLong
,传递一个行为如下的函数。首先,它使用LongConsumer
调用映射器函数,将替换元素累积到新创建的内部缓冲区中。当映射器函数返回时,它会从内部缓冲区创建一个LongStream
。最后,它将这个流返回给flatMapToLong
。 - 参数:
mapper
- 生成替换元素的 不干扰、无国籍的 函数- 返回:
- 新流
- 自从:
- 16
- 参见:
-
mapMultiToDouble
返回一个DoubleStream
,由用多个元素(特别是零个或多个元素)替换此流的每个元素的结果组成。通过将提供的映射函数与接受替换元素的consumer参数一起应用于每个元素来执行替换。映射函数零次或多次调用消费者以提供替换元素。这是一个 中间操作 。
如果 consumer 参数在其映射函数的应用范围之外使用,则结果未定义。
- 实现要求:
-
默认实现在此流上调用
flatMapToDouble
,传递一个行为如下的函数。首先,它使用DoubleConsumer
调用映射器函数,将替换元素累积到新创建的内部缓冲区中。当 mapper 函数返回时,它会从内部缓冲区创建一个DoubleStream
。最后,它将这个流返回给flatMapToDouble
。 - 参数:
mapper
- 生成替换元素的 不干扰、无国籍的 函数- 返回:
- 新流
- 自从:
- 16
- 参见:
-
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 元素,而且返回遇到顺序中的 first n 元素。如果您的情况的语义允许,使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
删除排序约束可能会导致并行管道中的limit()
显着加速。如果需要与遇到顺序保持一致,并且在并行管道中使用limit()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
的顺序执行可能会提高性能。 - 参数:
maxSize
- 流应限制为的元素数- 返回:
- 新流
- 抛出:
IllegalArgumentException
- 如果maxSize
为负
-
skip
- API 注意:
-
虽然
skip()
通常是顺序流管道上的廉价操作,但它在有序并行管道上可能非常昂贵,尤其是对于较大的n
值,因为skip(n)
不仅要跳过任何 n 元素,还要跳过遇到顺序中的 first n 元素。如果您的情况的语义允许,使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
删除排序约束可能会导致并行管道中的skip()
显着加速。如果需要与遇到顺序保持一致,并且在并行管道中使用skip()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
的顺序执行可能会提高性能。 - 参数:
n
- 要跳过的前导元素数- 返回:
- 新流
- 抛出:
IllegalArgumentException
- 如果n
为负
-
takeWhile
如果此流是有序的,则返回一个流,该流由从此流中获取的与给定谓词匹配的元素的最长前缀组成。否则,如果此流是无序的,则返回一个流,该流由从此流中获取的与给定谓词匹配的元素的子集组成。如果此流是有序的,则最长前缀是此流中与给定谓词匹配的元素的连续序列。序列的第一个元素是该流的第一个元素,紧跟在序列最后一个元素之后的元素不匹配给定的谓词。
如果这个流是无序的,并且这个流的一些(但不是全部)元素匹配给定的谓词,那么这个操作的行为是不确定的;可以自由获取匹配元素的任何子集(包括空集)。
独立于此流是有序的还是无序的如果此流的所有元素都匹配给定的谓词,则此操作获取所有元素(结果与输入相同),或者如果流中没有元素匹配给定的谓词则没有元素被采用(结果是一个空流)。
这是一个 短路状态中间操作 。
- API 注意:
-
虽然
takeWhile()
通常是顺序流管道上的廉价操作,但它在有序并行管道上可能非常昂贵,因为该操作被限制为不仅返回任何有效前缀,而且返回遇到顺序中元素的最长前缀。如果您的情况的语义允许,使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
删除排序约束可能会导致并行管道中的takeWhile()
显着加速。如果需要与遇到顺序保持一致,并且在并行管道中使用takeWhile()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
的顺序执行可能会提高性能。 - 实现要求:
-
默认实现获取此流的
spliterator
,包装该拆分器以支持此遍历操作的语义,并返回与包装的拆分器关联的新流。返回的流保留了该流的执行特征(即根据BaseStream.isParallel()
并行或顺序执行),但包装的拆分器可能会选择不支持拆分。当返回的流关闭时,将调用返回流和此流的关闭处理程序。 - 参数:
predicate
- 一个 不干扰 , 无国籍的 谓词应用于元素以确定元素的最长前缀。- 返回:
- 新流
- 自从:
- 9
-
dropWhile
如果此流是有序的,则返回一个流,该流由删除与给定谓词匹配的元素的最长前缀后的此流的剩余元素组成。否则,如果此流是无序的,则在删除与给定谓词匹配的元素子集后,返回由此流的剩余元素组成的流。如果此流是有序的,则最长前缀是此流中与给定谓词匹配的元素的连续序列。序列的第一个元素是该流的第一个元素,紧跟在序列最后一个元素之后的元素不匹配给定的谓词。
如果这个流是无序的,并且这个流的一些(但不是全部)元素匹配给定的谓词,那么这个操作的行为是不确定的;可以随意删除匹配元素的任何子集(包括空集)。
独立于此流是有序的还是无序的如果此流的所有元素都匹配给定的谓词,则此操作删除所有元素(结果是一个空流),或者如果流中没有元素匹配给定的谓词则不删除任何元素(结果与输入相同)。
这是一个 有状态的中间操作 。
- API 注意:
-
虽然
dropWhile()
通常是顺序流管道上的廉价操作,但它在有序并行管道上可能非常昂贵,因为操作被限制为不仅返回任何有效前缀,而且返回遇到顺序中元素的最长前缀。如果您的情况的语义允许,使用无序流源(例如generate(Supplier)
)或使用BaseStream.unordered()
删除排序约束可能会导致并行管道中的dropWhile()
显着加速。如果需要与遇到顺序保持一致,并且在并行管道中使用dropWhile()
时性能或内存利用率不佳,则切换到使用BaseStream.sequential()
的顺序执行可能会提高性能。 - 实现要求:
-
默认实现获取此流的
spliterator
,包装该拆分器以支持此遍历操作的语义,并返回与包装的拆分器关联的新流。返回的流保留了该流的执行特征(即根据BaseStream.isParallel()
并行或顺序执行),但包装的拆分器可能会选择不支持拆分。当返回的流关闭时,将调用返回流和此流的关闭处理程序。 - 参数:
predicate
- 一个 不干扰 , 无国籍的 谓词应用于元素以确定元素的最长前缀。- 返回:
- 新流
- 自从:
- 9
-
forEach
对此流的每个元素执行一个操作。这是一个 终端操作 。
此操作的行为是明确不确定的。对于并行流管道,此操作确实not保证尊重流的遇到顺序,因为这样做会牺牲并行性的好处。对于任何给定的元素,该操作可以在库选择的任何时间和任何线程中执行。如果操作访问共享状态,它负责提供所需的同步。
- 参数:
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
使用提供的标识值和 联想的 累加函数对此流的元素执行 减少,并返回减少的值。这等同于:
但不限于按顺序执行。T result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
identity
值必须是累加器函数的标识。这意味着对于所有t
,accumulator.apply(identity, t)
等于t
。accumulator
函数必须是 联想的 函数。这是一个 终端操作 。
- API 注意:
-
Sum、min、max、average 和字符串连接都是归约的特例。对数字流求和可以表示为:
或:Integer sum = integers.reduce(0, (a, b) -> a+b);
Integer sum = integers.reduce(0, Integer::sum);
虽然与简单地在循环中改变运行总数相比,这似乎是一种执行聚合的更迂回的方式,但缩减操作更优雅地并行化,不需要额外的同步,并且大大降低了数据竞争的风险。
- 参数:
identity
- 累积函数的标识值accumulator
- 一个 联想的 、 不干扰 、 无国籍的 函数用于组合两个值- 返回:
- 减少的结果
-
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
函数必须是 联想的 函数。这是一个 终端操作 。
- 参数:
accumulator
- 一个 联想的 、 不干扰 、 无国籍的 函数用于组合两个值- 返回:
-
一个
Optional
描述减少的结果 - 抛出:
NullPointerException
- 如果归约结果为空- 参见:
-
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
<R> R collect(Supplier <R> supplier, BiConsumer <R, ? super T > accumulator, BiConsumer <R, R> combiner) 对此流的元素执行 可变减少 操作。可变缩减是这样一种缩减,其中缩减值是可变结果容器,例如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
- 一个 联想的 、 不干扰 、 无国籍的 函数接受两个部分结果容器并合并它们,它必须与累加器函数兼容。 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
中。列表中的元素将按照此流的遇到顺序(如果存在的话)。返回的List不可修改;调用任何 mutator 方法将始终导致抛出UnsupportedOperationException
。不保证返回列表的实现类型或可序列化性。返回的实例可能是 value-based 。调用者不应假设返回实例的身份。这些实例上的身份敏感操作(引用相等性 (
==
)、身份哈希码和同步)是不可靠的,应该避免。这是一个 终端操作 。
- API 注意:
-
如果需要对返回的对象进行更多控制,请使用
Collectors.toCollection(Supplier)
。 - 实现要求:
-
此接口中的实现返回一个由以下内容生成的列表:
Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
- 实现注意事项:
- Stream 的大多数实例将重写此方法并提供与此接口中的实现相比高度优化的实现。
- 返回:
- 包含流元素的列表
- 自从:
- 16
-
min
- 参数:
comparator
- a 不干扰 , 无国籍的Comparator
比较这个流的元素- 返回:
-
一个
Optional
描述这个流的最小元素,或者一个空的Optional
如果流是空的 - 抛出:
NullPointerException
- 如果最小元素为空
-
max
- 参数:
comparator
- a 不干扰 , 无国籍的Comparator
比较这个流的元素- 返回:
-
一个
Optional
描述这个流的最大元素,或者一个空的Optional
如果流是空的 - 抛出:
NullPointerException
- 如果最大元素为空
-
count
long count()- API 注意:
-
如果实现能够直接从流源计算计数,则它可以选择不执行流管道(顺序或并行)。在这种情况下,不会遍历任何源元素,也不会评估任何中间操作。具有副作用的行为参数可能会受到影响,除了调试等无害情况外,强烈建议不要这样做。例如,考虑以下流:
流源 aList<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
- 如果选择的元素为空
-
findAny
返回描述流中某些元素的Optional
,如果流为空,则返回空的Optional
。这是一个 短路端子操作 。
此操作的行为显然是不确定的;可以自由选择流中的任何元素。这是为了在并行操作中实现最大性能;代价是对同一源的多次调用可能不会返回相同的结果。 (如果需要稳定的结果,请改用
findFirst()
。)- 返回:
-
一个
Optional
描述这个流的一些元素,或者一个空的Optional
如果流是空的 - 抛出:
NullPointerException
- 如果选择的元素为空- 参见:
-
builder
返回Stream
的构建器。- 类型参数:
T
- 元素类型- 返回:
- 流生成器
-
empty
返回一个空的顺序Stream
。- 类型参数:
T
- 流元素的类型- 返回:
- 一个空的顺序流
-
of
返回包含单个元素的顺序Stream
。- 类型参数:
T
- 流元素的类型- 参数:
t
- 单个元素- 返回:
- 单例顺序流
-
ofNullable
返回包含单个元素的顺序Stream
(如果非空),否则返回空的Stream
。- 类型参数:
T
- 流元素的类型- 参数:
t
- 单个元素- 返回:
- 如果指定的元素为非空,则为具有单个元素的流,否则为空流
- 自从:
- 9
-
of
返回其元素为指定值的顺序有序流。- 类型参数:
T
- 流元素的类型- 参数:
values
- 新流的元素- 返回:
- 新流
-
iterate
返回由函数f
迭代应用到初始元素seed
产生的无限顺序有序Stream
,产生由seed
、f(seed)
、f(f(seed))
等组成的Stream
。Stream
中的第一个元素(位置0
)将是提供的seed
。对于n > 0
,位置n
的元素将是将函数f
应用于位置n - 1
的元素的结果。对一个元素应用
f
的动作 发生之前 对后续元素应用f
的动作。对于任何给定的元素,操作可以在库选择的任何线程中执行。- 类型参数:
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
- 自从:
- 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
- 第二个流- 返回:
- 两个输入流的连接
-