tangguo

通过谓词限制流

java

是否存在Java 8流操作来限制(可能是无限的)Stream直到第一个元素与谓词不匹配?

在Java 9中,我们可以takeWhile像下面的示例那样使用它来打印所有小于10的数字。

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

由于Java 8中没有这样的操作,以一般方式实现它的最佳方法是什么?


阅读 270

收藏
2020-10-13

共2个答案

小编典典

这样的操作在Java 8中应该是可能的Stream,但不一定能有效地完成-例如,您不必并行化这样的操作,因为您必须按顺序查看元素。

该API并没有提供一种简便的方法,但是最简单的方法可能是采用Stream.iterator(),将其包装Iterator为具有“ take-while”的实现,然后返回到Spliterator然后是a Stream。或者-也许-包装Spliterator,尽管在此实现中它实际上不能再拆分了。

下面是一个未经测试的执行takeWhile上Spliterator

static <T> Spliterator<T> takeWhile(
    Spliterator<T> splitr, Predicate<? super T> predicate) {
  return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
    boolean stillGoing = true;
    @Override public boolean tryAdvance(Consumer<? super T> consumer) {
      if (stillGoing) {
        boolean hadNext = splitr.tryAdvance(elem -> {
          if (predicate.test(elem)) {
            consumer.accept(elem);
          } else {
            stillGoing = false;
          }
        });
        return hadNext && stillGoing;
      }
      return false;
    }
  };
}

static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
   return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}
2020-10-13
小编典典

操作takeWhiledropWhile已添加到JDK9。您的示例代码

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

在JDK 9下编译和运行时,其行为将完全符合您的预期。

JDK 9已发布。可从以下位置下载:JDK 9 Releases。

2020-10-13