jdk8中stream流的思想

q1871901600 发布于 2024-11-05 20 次阅读


在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() 等
  • 终止操作(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);
                }
            };
        }
    };
}

这些流操作当中实现了函数式接口的有哪几个?

  1. map(Function<? super T, ? extends R> mapper):将流中的每个元素映射到另一个元素上,使用Function接口。
  2. filter(Predicate<? super T> predicate):根据给定的谓词过滤流中的元素,使用Predicate接口。
  3. forEach(Consumer<? super T> action):对流中的每个元素执行操作,使用Consumer接口。
  4. sorted(Comparator<? super T> comparator):根据比较器对流中的元素进行排序,使用Comparator接口。
  5. reduce(BinaryOperator<T> accumulator):通过某个连接动作将所有元素汇总成一个汇总结果,使用BinaryOperator接口。
  6. anyMatch(Predicate<? super T> predicate):如果流中至少有一个元素匹配给定的谓词,则返回true,使用Predicate接口。
  7. allMatch(Predicate<? super T> predicate):如果流中的所有元素都匹配给定的谓词,则返回true,使用Predicate接口。
  8. noneMatch(Predicate<? super T> predicate):如果流中没有元素匹配给定的谓词,则返回true,使用Predicate接口。
  9. findFirst():返回流中的第一个元素,如果流为空则返回一个空的Optional
  10. findAny():返回流中的任意一个元素,如果流为空则返回一个空的Optional
  11. collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner):将流转换成其他形式的结果,使用SupplierBiConsumer接口。
  12. flatMap(Function<? super T, ? extends Stream<? extends R>> mapper):将流中的每个元素替换为目标流,然后将多个流连接到一个流,使用Function接口。

这些方法中的函数式接口允许你以声明式的方式处理集合,使得代码更加简洁和表达性强。通过传递Lambda表达式或方法引用,你可以轻松地实现这些接口。

参考文章;

原来你是这样的 Stream —— 浅析 Java Stream 实现原理 - 知乎

一个会写python的Java工程师
最后更新于 2024-11-14