【发布时间】:2013-11-06 02:37:41
【问题描述】:
Java 8 引入了一个类似于 Scala 的 Stream 的 Stream 类,这是一个强大的惰性结构,使用它可以非常简洁地执行以下操作:
def from(n: Int): Stream[Int] = n #:: from(n+1)
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail filter (_ % s.head != 0))
}
val primes = sieve(from(2))
primes takeWhile(_ < 1000) print // prints all primes less than 1000
我想知道在 Java 8 中是否可以做到这一点,所以我写了这样的东西:
IntStream from(int n) {
return IntStream.iterate(n, m -> m + 1);
}
IntStream sieve(IntStream s) {
int head = s.findFirst().getAsInt();
return IntStream.concat(IntStream.of(head), sieve(s.skip(1).filter(n -> n % head != 0)));
}
IntStream primes = sieve(from(2));
相当简单,但它会产生java.lang.IllegalStateException: stream has already been operated upon or closed,因为findFirst() 和skip() 都是对Stream 的终端操作,只能执行一次。
我真的不需要用完两次流,因为我只需要流中的第一个数字,其余的作为另一个流,即相当于 Scala 的 Stream.head 和 Stream.tail。 Java 8 Stream 中是否有可以用来实现此目的的方法?
谢谢。
【问题讨论】:
-
如果你想以这种方式操作流,你能做的最好的可能就是包装它的
iterator()。 (更不用说你的实现实际上不是一个合适的素筛;参见例如this paper。) -
我已经尝试提取第一个数字并重建另一个流,如
IntStream.generate(() -> it.next()),但迭代器的hasNext()急切地工作并导致无限递归。 -
是的,这行不通。真的,这对
Streams 根本不起作用。 -
查看 blog post 了解如何在 Java 中自己构建惰性序列。
-
我 programmed this recently 使用 JDK8,但我构建了自己的流,因为我不认为 JDK 8 流与 scala 的惰性流完全相同。
标签: java scala java-8 java-stream sieve