SwitchIfEmpty链导致StackOverflowError。

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

SwitchIfEmpty Chain results in StackOverflowError

问题

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

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

示例

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

  1. public class SwitchIfEmptyTest {
  2. public static void main(String[] args) {
  3. SwitchIfEmptyDemo demo = new SwitchIfEmptyDemo();
  4. demo.one("foo")
  5. .blockingForEach(s -> System.out.println(s));
  6. }
  7. static class SwitchIfEmptyDemo {
  8. private SomeSource source = new SomeSource();
  9. public Flowable<String> one(String input) {
  10. return Flowable.<String>empty()
  11. .switchIfEmpty(two(input));
  12. }
  13. public Flowable<String> two(String input) {
  14. return Flowable.<String>create(emitter -> {
  15. emitter.onNext(input);
  16. emitter.onComplete();
  17. }, BackpressureStrategy.ERROR)
  18. .flatMap(inputFlowable -> {
  19. return source.read()
  20. .toList()
  21. .toFlowable()
  22. .flatMap(strings -> {
  23. Flowable<String> flowable = Flowable.empty();
  24. for (String s : strings) {
  25. flowable = flowable.switchIfEmpty(third(s));
  26. }
  27. return flowable;
  28. });
  29. });
  30. }
  31. public Flowable<String> third(String input) {
  32. //System.out.println("Value " + input);
  33. return Flowable.empty();
  34. }
  35. }
  36. static class SomeSource {
  37. public Flowable<String> read() {
  38. return Flowable.create(emitter -> {
  39. for (int i = 0; i < 1_000_000; i++) {
  40. emitter.onNext("Some values " + i);
  41. }
  42. emitter.onComplete();
  43. }, BackpressureStrategy.ERROR);
  44. }
  45. }
  46. }

堆栈跟踪

  1. Exception in thread "main" java.lang.StackOverflowError
  2. at java.lang.ClassLoader.defineClass1(Native Method)
  3. at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
  4. at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
  5. at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
  6. at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
  7. at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
  8. at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
  9. at java.security.AccessController.doPrivileged(Native Method)
  10. at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
  11. at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
  12. at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
  13. at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
  14. at io.reactivex.Flowable.subscribe(Flowable.java:14939)
  15. at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
  16. at io.reactivex.Flowable.subscribe(Flowable.java:14935)
  17. at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
  18. at io.reactivex.Flowable.subscribe(Flowable.java:14935)
  19. at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
  20. ...
英文:

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.

  1. public class SwitchIfEmptyTest {
  2. public static void main(String[] args) {
  3. SwitchIfEmptyDemo demo = new SwitchIfEmptyDemo();
  4. demo.one(&quot;foo&quot;)
  5. .blockingForEach(s -&gt; System.out.println(s));
  6. }
  7. static class SwitchIfEmptyDemo {
  8. private SomeSource source = new SomeSource();
  9. public Flowable&lt;String&gt; one(String input) {
  10. return Flowable.&lt;String&gt;empty()
  11. .switchIfEmpty(two(input));
  12. }
  13. public Flowable&lt;String&gt; two(String input) {
  14. return Flowable.&lt;String&gt;create(emitter -&gt; {
  15. emitter.onNext(input);
  16. emitter.onComplete();
  17. }, BackpressureStrategy.ERROR)
  18. .flatMap(inputFlowable -&gt; {
  19. return source.read()
  20. .toList()
  21. .toFlowable()
  22. .flatMap(strings -&gt; {
  23. Flowable&lt;String&gt; flowable = Flowable.empty();
  24. for (String s : strings) {
  25. flowable = flowable.switchIfEmpty(third(s));
  26. }
  27. return flowable;
  28. });
  29. });
  30. }
  31. public Flowable&lt;String&gt; third(String input) {
  32. //System.out.println(&quot;Value &quot; + input);
  33. return Flowable.empty();
  34. }
  35. }
  36. static class SomeSource {
  37. public Flowable&lt;String&gt; read() {
  38. return Flowable.create(emitter -&gt; {
  39. for (int i = 0; i &lt; 1_000_000; i++) {
  40. emitter.onNext(&quot;Some values &quot; + i);
  41. }
  42. emitter.onComplete();
  43. }, BackpressureStrategy.ERROR);
  44. }
  45. }
  46. }

Stacktrace

  1. Exception in thread &quot;main&quot; java.lang.StackOverflowError
  2. at java.lang.ClassLoader.defineClass1(Native Method)
  3. at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
  4. at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
  5. at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
  6. at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
  7. at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
  8. at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
  9. at java.security.AccessController.doPrivileged(Native Method)
  10. at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
  11. at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
  12. at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
  13. at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
  14. at io.reactivex.Flowable.subscribe(Flowable.java:14939)
  15. at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
  16. at io.reactivex.Flowable.subscribe(Flowable.java:14935)
  17. at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
  18. at io.reactivex.Flowable.subscribe(Flowable.java:14935)
  19. at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
  20. ...

答案1

得分: 0

以下是翻译好的内容:

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

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

  1. public Flowable<String> two(String input) {
  2. return Flowable.<String>create(emitter -> {
  3. emitter.onNext(input);
  4. emitter.onComplete();
  5. }, BackpressureStrategy.ERROR)
  6. .flatMap(inputFlowable -> {
  7. return source.read()
  8. .flatMap(this::third)
  9. .takeWhile(s -> s.equals("false"));
  10. });
  11. }
英文:

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

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

  1. public Flowable&lt;String&gt; two(String input) {
  2. return Flowable.&lt;String&gt;create(emitter -&gt; {
  3. emitter.onNext(input);
  4. emitter.onComplete();
  5. }, BackpressureStrategy.ERROR)
  6. .flatMap(inputFlowable -&gt; {
  7. return source.read()
  8. .flatMap(this::third)
  9. .takeWhile(s -&gt; s.equals(&quot;false&quot;));
  10. });
  11. }

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:

确定