SwitchIfEmpty链导致StackOverflowError。

huangapple go评论83阅读模式
英文:

SwitchIfEmpty Chain results in StackOverflowError

问题

以下代码会导致 StackOverflowError。在编写类似这样的代码时,这是否应该发生,还是说这是框架中需要解决的问题?

该代码已在 rxjava-2.2.19 中进行了测试。代码源可以在此处找到。

示例

以下代码基于我们用来实现某种带有中断条件的循环的代码(参见 flowable = flowable.switchIfEmpty(third(s)))。显然,这种方法并不奏效。

public class SwitchIfEmptyTest {

    public static void main(String[] args) {
        SwitchIfEmptyDemo demo = new SwitchIfEmptyDemo();
        demo.one("foo")
            .blockingForEach(s -> System.out.println(s));
    }

    static class SwitchIfEmptyDemo {

        private SomeSource source = new SomeSource();

        public Flowable<String> one(String input) {
            return Flowable.<String>empty()
                .switchIfEmpty(two(input));
        }

        public Flowable<String> two(String input) {
            return Flowable.<String>create(emitter -> {
                emitter.onNext(input);
                emitter.onComplete();
            }, BackpressureStrategy.ERROR)
                .flatMap(inputFlowable -> {
                    return source.read()
                        .toList()
                        .toFlowable()
                        .flatMap(strings -> {
                            Flowable<String> flowable = Flowable.empty();
                            for (String s : strings) {
                                flowable = flowable.switchIfEmpty(third(s));
                            }
                            return flowable;
                        });
                });
        }

        public Flowable<String> third(String input) {
            //System.out.println("Value " + input);
            return Flowable.empty();
        }
    }

    static class SomeSource {

        public Flowable<String> read() {
            return Flowable.create(emitter -> {
                for (int i = 0; i < 1_000_000; i++) {
                    emitter.onNext("Some values " + i);
                }
                emitter.onComplete();
            }, BackpressureStrategy.ERROR);
        }
    }
}

堆栈跟踪

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
    at io.reactivex.Flowable.subscribe(Flowable.java:14939)
    at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
    at io.reactivex.Flowable.subscribe(Flowable.java:14935)
    at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
    at io.reactivex.Flowable.subscribe(Flowable.java:14935)
    at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
    ...
英文:

The following code results in a StackOverflowError. Is this supposed to happen when writing code like this or is it something that needs to be addressed in the framework?

The code has been tested with rxjava-2.2.19. Sources can be found here.

Sample

The following code is based on code we use to accomplish some sort of looping with a break condition (see flowable = flowable.switchIfEmpty(third(s))). Apparently this approach is not working quite well.

public class SwitchIfEmptyTest {
public static void main(String[] args) {
SwitchIfEmptyDemo demo = new SwitchIfEmptyDemo();
demo.one(&quot;foo&quot;)
.blockingForEach(s -&gt; System.out.println(s));
}
static class SwitchIfEmptyDemo {
private SomeSource source = new SomeSource();
public Flowable&lt;String&gt; one(String input) {
return Flowable.&lt;String&gt;empty()
.switchIfEmpty(two(input));
}
public Flowable&lt;String&gt; two(String input) {
return Flowable.&lt;String&gt;create(emitter -&gt; {
emitter.onNext(input);
emitter.onComplete();
}, BackpressureStrategy.ERROR)
.flatMap(inputFlowable -&gt; {
return source.read()
.toList()
.toFlowable()
.flatMap(strings -&gt; {
Flowable&lt;String&gt; flowable = Flowable.empty();
for (String s : strings) {
flowable = flowable.switchIfEmpty(third(s));
}
return flowable;
});
});
}
public Flowable&lt;String&gt; third(String input) {
//System.out.println(&quot;Value &quot; + input);
return Flowable.empty();
}
}
static class SomeSource {
public Flowable&lt;String&gt; read() {
return Flowable.create(emitter -&gt; {
for (int i = 0; i &lt; 1_000_000; i++) {
emitter.onNext(&quot;Some values &quot; + i);
}
emitter.onComplete();
}, BackpressureStrategy.ERROR);
}
}
}

Stacktrace

Exception in thread &quot;main&quot; java.lang.StackOverflowError
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at io.reactivex.Flowable.subscribe(Flowable.java:14939)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
at io.reactivex.Flowable.subscribe(Flowable.java:14935)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
at io.reactivex.Flowable.subscribe(Flowable.java:14935)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
...

答案1

得分: 0

以下是翻译好的内容:

为了消除 StackOverflowError,一种可能性是使用 takeWhile 操作符(详见完整差异)。

<!-- language: lang-java -->

public Flowable<String> two(String input) {
    return Flowable.<String>create(emitter -> {
        emitter.onNext(input);
        emitter.onComplete();
    }, BackpressureStrategy.ERROR)
    .flatMap(inputFlowable -> {
        return source.read()
            .flatMap(this::third)
            .takeWhile(s -> s.equals("false"));
    });
}
英文:

In order to get rid of the StackOverflowError, one possibility is to use the takeWhile operator (see full diff).

<!-- language: lang-java -->

public Flowable&lt;String&gt; two(String input) {
return Flowable.&lt;String&gt;create(emitter -&gt; {
emitter.onNext(input);
emitter.onComplete();
}, BackpressureStrategy.ERROR)
.flatMap(inputFlowable -&gt; {
return source.read()
.flatMap(this::third)
.takeWhile(s -&gt; s.equals(&quot;false&quot;));
});
}

huangapple
  • 本文由 发表于 2020年8月20日 00:08:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/63490987.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定