在java中我们处理一个集合中的数据常用的for循环直接处理这些数据。
for( int i = 0; i < list.size(); i++) {
if (list.get(i).startsWith("a")) {
tempList.add(list.get(i));
}
}
但是如果将所有操作 筛选、切片、映射、查找、去除重复,统计,匹配和归约,都写在for循环中必然会出现多重循环的情况,使得代码可读性很差的情况。那么采用流的形式就要清晰很多。
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(System.out::println);
流就是像流水线一样执行各个操作,最终得到新的集合,如下图所示:


原理

ReferencePipeline 包含了控制数据流入的 Head ,中间操作 StatelessOp, StatefulOp
,终止操作 TerminalOp
。
Stream 常用的流操作包括:
- 中间操作(Intermediate Operations)
- 无状态(Stateless)操作:每个数据的处理是独立的,不会影响或依赖之前的数据。如
filter()
、flatMap()
、flatMapToDouble()
、flatMapToInt()
、flatMapToLong()
、map()
、mapToDouble()
、mapToInt()
、mapToLong()
、peek()
、unordered()
等 - 有状态(Stateful)操作:处理时会记录状态,比如处理了几个。后面元素的处理会依赖前面记录的状态,或者拿到所有元素才能继续下去。如
distinct()
、sorted()
、sorted(comparator)
、limit()
、skip()
等
- 无状态(Stateless)操作:每个数据的处理是独立的,不会影响或依赖之前的数据。如
- 终止操作(Terminal Operations)
- 非短路操作:处理完所有数据才能得到结果。如
collect()
、count()
、forEach()
、forEachOrdered()
、max()
、min()
、reduce()
、toArray()
等。 - 短路(short-circuiting)操作:拿到符合预期的结果就会停下来,不一定会处理完所有数据。如
anyMatch()
、allMatch()
、noneMatch()
、findFirst()
、findAny()
等。
- 非短路操作:处理完所有数据才能得到结果。如
filter方法的源码:
@Override
public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
Objects.requireNonNull(predicate);
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SIZED) {
@Override
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override
public void begin(long size) {
downstream.begin(-1);
}
@Override
public void accept(P_OUT u) {
if (predicate.test(u))
downstream.accept(u);
}
};
}
};
}
这些流操作当中实现了函数式接口的有哪几个?
map(Function<? super T, ? extends R> mapper)
:将流中的每个元素映射到另一个元素上,使用Function
接口。filter(Predicate<? super T> predicate)
:根据给定的谓词过滤流中的元素,使用Predicate
接口。forEach(Consumer<? super T> action)
:对流中的每个元素执行操作,使用Consumer
接口。sorted(Comparator<? super T> comparator)
:根据比较器对流中的元素进行排序,使用Comparator
接口。reduce(BinaryOperator<T> accumulator)
:通过某个连接动作将所有元素汇总成一个汇总结果,使用BinaryOperator
接口。anyMatch(Predicate<? super T> predicate)
:如果流中至少有一个元素匹配给定的谓词,则返回true
,使用Predicate
接口。allMatch(Predicate<? super T> predicate)
:如果流中的所有元素都匹配给定的谓词,则返回true
,使用Predicate
接口。noneMatch(Predicate<? super T> predicate)
:如果流中没有元素匹配给定的谓词,则返回true
,使用Predicate
接口。findFirst()
:返回流中的第一个元素,如果流为空则返回一个空的Optional
。findAny()
:返回流中的任意一个元素,如果流为空则返回一个空的Optional
。collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
:将流转换成其他形式的结果,使用Supplier
,BiConsumer
接口。flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
:将流中的每个元素替换为目标流,然后将多个流连接到一个流,使用Function
接口。
这些方法中的函数式接口允许你以声明式的方式处理集合,使得代码更加简洁和表达性强。通过传递Lambda表达式或方法引用,你可以轻松地实现这些接口。
参考文章;
Comments NOTHING