Java 8 引入了Stream http://download.java.net/jdk8/docs/api/java/util/stream/Stream.html类似于 Scala 的类Stream http://www.scala-lang.org/files/archive/nightly/docs/library/scala/collection/immutable/Stream.html,一个强大的惰性构造,使用它可以非常简洁地执行类似的操作:
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()
and skip()
终端操作是否在Stream
只能进行一次。
我实际上不必使用该流两次,因为我需要的只是流中的第一个数字,其余的作为另一个流,即相当于 Scala 的Stream.head
and Stream.tail
。 Java 8中有一个方法Stream
我可以用它来实现这个目标吗?
Thanks.
即使您没有无法拆分的问题IntStream
,您的代码不起作用,因为您正在调用您的sieve
递归方法而不是惰性方法。因此,在查询结果流中的第一个值之前,您需要进行无限递归。
分裂一个IntStream s
成头和尾IntStream
(尚未消耗)是可能的:
PrimitiveIterator.OfInt it = s.iterator();
int head = it.nextInt();
IntStream tail = IntStream.generate(it::next).filter(i -> i % head != 0);
在这个地方你需要一个调用的结构sieve
懒洋洋地放在尾巴上。Stream
没有规定;concat
期望现有流实例作为参数,并且您无法构造调用的流sieve
使用 lambda 表达式进行延迟创建,因为延迟创建仅适用于 lambda 表达式不支持的可变状态。如果您没有隐藏可变状态的库实现,则必须使用可变对象。但是,一旦您接受可变状态的要求,解决方案可能比您的第一种方法更容易:
IntStream primes = from(2).filter(i -> p.test(i)).peek(i -> p = p.and(v -> v % i != 0));
IntPredicate p = x -> true;
IntStream from(int n)
{
return IntStream.iterate(n, m -> m + 1);
}
这将递归地创建一个过滤器,但最终是否创建一个树并不重要IntPredicate
s 或一棵树IntStream
s(就像你的IntStream.concat
方法(如果有效的话)。如果您不喜欢过滤器的可变实例字段,您可以将其隐藏在内部类中(但不能隐藏在 lambda 表达式中……)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)