gpt4 book ai didi

Java 8 Stream,得到头和尾

转载 作者:IT老高 更新时间:2023-10-28 20:35:24 27 4
gpt4 key购买 nike

Java 8 引入了 Stream类似于 Scala 的 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 operating on or closed 因为 findFirst()skip()Stream 上的终端操作,只能执行一次。

我真的不需要用完流两次,因为我只需要流中的第一个数字,其余的作为另一个流,即等效于 Scala 的 Stream.headStream.tail。我可以使用 Java 8 Stream 中的方法来实现此目的吗?

谢谢。

最佳答案

即使您没有无法拆分 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 期望现有的流实例作为参数,并且您不能使用 lambda 表达式构造一个调用 sieve 的流,因为延迟创建仅适用于 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 的树还是 IntStream 的树(就像您的IntStream.concat 方法(如果它确实有效)。如果您不喜欢过滤器的可变实例字段,您可以将其隐藏在内部类中(但不能隐藏在 lambda 表达式中……)。

关于Java 8 Stream,得到头和尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19803058/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com