How to replace 'if statement' with rx-java for avoiding callback hell?

To avoid the if/else and to not break the chain™, I like to use publish and merge to split and re-merge the stream:

apiResultStream
  .publish(results -> 
    Observable.merge(
        results.filter(result -> result.response == true)
               .flatmap(result -> callSuccessApiObservable()),
        results.filter(result -> result.response == false)
               .flatmap(result -> callFailureApiObservable())
    )
  )
  .subscribe(...

There are loads of ways of doing this and it really depends on your use case. In general I wouldn't want to split into 2 streams, as that makes your code less readable. Also, I'm not sure what benefit you get from the flatMap call. There's nothing wrong with doing if stuff within a map call.

Here are a few options:

1 - For adding logging (a bit like your print lines), I use doOnEach()

apiResultStream
  .doOnEach(next -> {
    if (next) logger.info("Logging true " + next);
    else  logger.info(Logging false " + next);
  })
  .subscribe(....

2 - The work you're doing is part of your stream, and you're going to want to do more work on the stream later - use map

apiResultStream
  .map(next -> {
        if (next) doSomeCallWithNextWhenTrue(next);
        else doSomeCallwithNextWhenFalse(next);
      })
  .subscribe(...

3 - If this is work you want to do at the end of the pipeline - IE after all transformational or other stream like work has completed, then do it in the subscribe call.

apiResultStream
  .subscribe(next -> {
            if (next) doSomeCallWithNextWhenTrue(next);
            else doSomeCallwithNextWhenFalse(next);
          });

The problem is - with such a simple use case, it's difficult to suggest the best option, but I appreciate that in learning Rx, working out how to do conditional statements can seem confusing. In general, I just use map or flatMap when I'm calling another method that returns an Observable and do my logic in there.

Update

Still not sure why you're splitting your streams. Unless you start getting clever with different threads, the first subscribe call is going to block the second which is probably not what you want. Also, if you don't call subscribe more than once, then you don't need the cache() call.

There's nothing wrong with using an if statement within an map / flatmap / subscribe. Especially if it makes your code more readable.

I would do the following:

apiResultStream
  .flatMap(result -> {
    if (result.response == true) {
      return callSuccessApi(result)
    }
    else {
      return callFailureApi(result)
  })
  //Do any more calls you need
  .subscribe(...

So much cleaner.

I'm a bit confused by your System.out.println calls in subscribe. Is this there for debug or logging purposes? If so, just do that within the above flatMap in the if statement.

Hope this helps,

Will

Tags:

Java

Rx Java