Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 用LongStream和jOOλ生成素数;导致堆栈溢出错误_Java_Java 8_Stack Overflow_Java Stream - Fatal编程技术网

Java 用LongStream和jOOλ生成素数;导致堆栈溢出错误

Java 用LongStream和jOOλ生成素数;导致堆栈溢出错误,java,java-8,stack-overflow,java-stream,Java,Java 8,Stack Overflow,Java Stream,出于教育目的,我想使用Java-8创建一个素数流。这是我的方法。如果数x的素数因子不超过sqrt(x),则该数为素数。所以假设我已经有一个素数流,我可以用以下谓词检查它: x -> Seq.seq(primes()).limitWhile(p -> p <= Math.sqrt(x)).allMatch(p -> x % p != 0) prev -> LongStream.iterate(prev + 1, i -> i + 1)

出于教育目的,我想使用Java-8创建一个素数流。这是我的方法。如果数
x
的素数因子不超过
sqrt(x)
,则该数为素数。所以假设我已经有一个素数流,我可以用以下谓词检查它:

x -> Seq.seq(primes()).limitWhile(p -> p <= Math.sqrt(x)).allMatch(p -> x % p != 0)
prev -> LongStream.iterate(prev + 1, i -> i + 1)
                  .filter(x -> Seq.seq(primes()).limitWhile(p -> p <= Math.sqrt(x))
                                                .allMatch(p -> x % p != 0))
                  .findFirst()
                  .getAsLong()
将所有内容放在一起,我编写了以下
primes()
方法:

public static LongStream primes() {
    return LongStream.iterate(2L, 
            prev -> LongStream.iterate(prev + 1, i -> i + 1)
                              .filter(x -> Seq.seq(primes())
                                              .limitWhile(p -> p <= Math.sqrt(x))
                                              .allMatch(p -> x % p != 0))
                              .findFirst()
                              .getAsLong());
}
不幸的是,它失败了,出现了令人不快的
StackOverflowerError
,如下所示:

Exception in thread "main" java.lang.StackOverflowError
at java.util.stream.ReferencePipeline$StatelessOp.opIsStateful(ReferencePipeline.java:624)
at java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:211)
at java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94)
at java.util.stream.ReferencePipeline$StatelessOp.<init>(ReferencePipeline.java:618)
at java.util.stream.LongPipeline$3.<init>(LongPipeline.java:225)
at java.util.stream.LongPipeline.mapToObj(LongPipeline.java:224)
at java.util.stream.LongPipeline.boxed(LongPipeline.java:201)
at org.jooq.lambda.Seq.seq(Seq.java:2481)
at Primes.lambda$2(Primes.java:13)
at Primes$$Lambda$4/1555009629.test(Unknown Source)
at java.util.stream.LongPipeline$8$1.accept(LongPipeline.java:324)
at java.util.Spliterators$LongIteratorSpliterator.tryAdvance(Spliterators.java:2009)
at java.util.stream.LongPipeline.forEachWithCancel(LongPipeline.java:160)
at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:529)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:516)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.LongPipeline.findFirst(LongPipeline.java:474)
at Primes.lambda$0(Primes.java:14)
at Primes$$Lambda$1/918221580.applyAsLong(Unknown Source)
at java.util.stream.LongStream$1.nextLong(LongStream.java:747)
at java.util.Spliterators$LongIteratorSpliterator.tryAdvance(Spliterators.java:2009)
...
现在它就像一个符咒!不是很快,但在几分钟内我得到的质数超过1000000,没有任何例外。结果正确,可对照素数表进行检查:

System.out.println(primes().skip(9999).findFirst());
// prints Optional[104729] which is actually 10000th prime.
public static LongStream primes() {
    return LongStream.iterate(2L,
        prev -> prev == 2 ? 3 : 
                prev == 3 ? 5 :
                LongStream.iterate(prev + 1, i -> i + 1)
                        .filter(x -> Seq.seq(primes())
                            .limitWhile(p -> p <= Math.sqrt(x))
                            .allMatch(p -> x % p != 0)
                        ).findFirst()
                        .getAsLong());
所以问题是:第一个基于
的LongStream
版本有什么问题?是jOOλbug、JDK bug还是我做错了什么


请注意,我对生成素数的其他方法不感兴趣,我想知道这个特定代码有什么问题。

当通过
迭代
生成流时,
长流
的行为似乎不同。以下代码说明了区别:

LongStream.iterate(1, i -> {
    System.out.println("LongStream incrementing " + i);
    return i + 1;
}).limit(1).count();

Stream.iterate(1L, i -> {
    System.out.println("Stream incrementing " + i);
    return i + 1;
}).limit(1).count();
输出是

长流递增1

因此,即使只需要第一个元素,
LongStream
也会调用该函数,而
Stream
则不会。这就解释了您将遇到的异常

我不知道这是否应该被称为bug。Javadoc没有以这种或那种方式指定这种行为,尽管如果它是一致的就好了

解决此问题的一种方法是硬编码素数的初始序列:

System.out.println(primes().skip(9999).findFirst());
// prints Optional[104729] which is actually 10000th prime.
public static LongStream primes() {
    return LongStream.iterate(2L,
        prev -> prev == 2 ? 3 : 
                prev == 3 ? 5 :
                LongStream.iterate(prev + 1, i -> i + 1)
                        .filter(x -> Seq.seq(primes())
                            .limitWhile(p -> p <= Math.sqrt(x))
                            .allMatch(p -> x % p != 0)
                        ).findFirst()
                        .getAsLong());
公共静态长流素数(){
返回LongStream.iterate(2L,
上一个->上一个==2?3:
上一个==3?5:
LongStream.iterate(prev+1,i->i+1)
.filter(x->Seq.Seq(primes())
.limitWhile(p->px%p!=0)
).findFirst()
.getAsLong());

< /代码> 您可以以更简单的方式产生这种差异。考虑下面两个版本(同样无效)的递归长枚举流,它可以被称为下面的序列以产生1-5:

的序列。
longs().limit(5).forEach(System.out::println);
将导致相同的堆栈溢出错误 行得通 与
LongStream.iterate()
版本不同:

    final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
        long t = seed;

        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public long nextLong() {
            long v = t;
            t = f.applyAsLong(t);
            return v;
        }
    };
请注意,装箱迭代器仅在返回种子后调用函数,而原语迭代器在返回种子之前缓存下一个值

这意味着,当您将递归迭代函数与原语迭代器一起使用时,流中的第一个值永远不会生成,因为下一个值是提前获取的


这可能被报告为一个JDK错误,而且也不是JOOL。用等效的
x->primes().filter(p->p*p>x | | x%p==0)替换基于Seq的过滤器。findFirst().get()>Math.sqrt(x)
具有相同的行为。适用于
,但不适用于
长流
。感谢您提供了良好的分析和其他方法来暴露此问题。无需报告错误:在Java-9中,我已经修复了;-)@TagirValeev:很高兴知道。您有链接吗?您知道修复程序是否将后移植到Java 8?@TagirValeev:没关系。我很确定它不会被移植。
public static Stream<Long> longs() {
    return Stream.iterate(1L, i ->
        1L + longs().skip(i - 1L)
                    .findFirst()
                    .get());
}
    final Iterator<T> iterator = new Iterator<T>() {
        @SuppressWarnings("unchecked")
        T t = (T) Streams.NONE;

        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public T next() {
            return t = (t == Streams.NONE) ? seed : f.apply(t);
        }
    };
    final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
        long t = seed;

        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public long nextLong() {
            long v = t;
            t = f.applyAsLong(t);
            return v;
        }
    };