英文:
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("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);
}
}
}
Stacktrace
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)
...
答案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<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"));
});
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论