如何用rx-java替换'if语句'以避免回调地狱?

kya*_*nro 17 java rx-java

我试图用rx-java替换我的代码.(这是非常小的代码.)

它完成了它的工作原理.

但我想知道......

  1. 这是一个很好的Rx风格吗?
  2. 如果不好,请说明不好的一点

下面是我的api处理代码.

之前

Random r = new Random();
boolean apiResult = r.nextBoolean(); // it represents api result. ex. {"result": true} or {"result": false}

if (apiResult == true) {
    // do something

    System.out.println("result:" + "success");
} else {
    // do something

    System.out.println("result:" + "failure");
}
Run Code Online (Sandbox Code Playgroud)

Random r = new Random();
Observable<Boolean> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
    @Override
    public void call(Subscriber<? super Boolean> subscriber) {
        // emit true or false
         subscriber.onNext(r.nextBoolean());
    }
}).cache(1);


// I used filter for split. Is it Rx style?
// success if true emitted.
Observable<Boolean> successStream = apiResultStream
        .filter(aBoolean -> aBoolean == true); // here

// failure if false emitted.
Observable<Boolean> failureStream = apiResultStream
        .filter(aBoolean -> aBoolean == false); // here


// success flow
successStream
        .flatMap(aBoolean -> Observable.just("success"))
        // and do something
        .subscribe(aString -> System.out.println("result:" + aString));

// failure flow
failureStream
        .flatMap(aBoolean -> Observable.just("failure"))
        // and do something.
        // I want to keep subscriber.
        .subscribe(aString -> System.out.println("result:" + aString));
Run Code Online (Sandbox Code Playgroud)

编辑

我差点换掉.谢谢你的好评.
(但我有一些未替换的代码.它有很多回调和if语句.)

我想避免'回调地狱'.

关键是'callSuccessApi'和'callFailureApi'之间的结果类型不同

在rx之前

// callback hell!
callApi(new Callback<Result>(){
    @Override
    public void success(Result result) {
        if (result.Response == true) {
            callSuccessApi(new Callback<ResultSuccess>(){
                @Override
                public void success(ResultSuccess result) {
                    // and more callbacks...
                }
            }
        } else { // result.Response == false
            callFailureApi(new Callback<ResultFailure>(){
                @Override
                public void success(ResultFailure result) {
                    // and more callbacks...
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用rx之后(避免回调地狱!这是一个很好的Rx风格吗?)

// change 1st api to observable.(I changed other api to observable)
Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
    @Override
    public void call(Subscriber<? super Boolean> subscriber) {
        callApi(new Callback<Result>(){
            @Override
            public void success(Result result) {
                subscriber.onNext(result);
            }
        });
    }
}).cache(1); // ensure same Observable<Result> for success and failure.


// I used filter for split. Is it Rx style?
// success if result.response == true.
Observable<ResultSuccess> successStream = apiResultStream
        .filter(result -> result.response == true); // here

// failure if result.response == false.
Observable<ResultFailure> failureStream = apiResultStream
        .filter(result -> result.response == false); // here


// success flow. callSuccessApi return Observable<ResultSuccess>
successStream
        .flatMap(result -> callSuccessApi(result))
        // and more api call with flatMap...
        .subscribe(resultSuccessN -> System.out.println("result:" + resultSuccessN.toString()));

// failure flow. callFailureApi return Observable<ResultFailure>
failureStream
.flatMap(resultFailure -> callFailureApi(result))
        // and more api call with flatMap...
        .subscribe(resultFailureN -> System.out.println("result:" + resultFailureN.toString()));
Run Code Online (Sandbox Code Playgroud)

抱歉,我的英语很差,问题很长.

更新了我的代码

我在这个问题上得到了两个重要信息.(谢谢@TomášDvořák,@ Will

  1. 这是否是一个好的方式取决于具体情况.
  2. 在map/flatmap/subscribe中使用if语句没有错.

更新的代码

Observable<Result> apiResultStream = Observable.create(new OnSubscribe<Boolean>() {
        @Override
        public void call(Subscriber<? super Boolean> subscriber) {
            callApi(new Callback<Result>() {
                @Override
                public void success(Result result) {
                    subscriber.onNext(result);
                }
            });
        }
    });

    // In this case,   I used 'if' for simply and cleanly.
    apiResultStream
            .subscribe(result -> {
                if (result.response == true) {
                    callSuccessApi(); // this line looks like 'callback'. but I used this for simply and cleanly.
                } else {
                    callFailureApi();
                }
            });
Run Code Online (Sandbox Code Playgroud)

Wil*_*ill 13

有很多方法可以做到这一点,这取决于你的用例.一般来说,我不想分成2个流,因为这会使你的代码不那么可读.另外,我不确定你从flatMap调用中获得了什么好处.如果在地图调用中进行操作,则没有任何问题.

以下是一些选项:

1 - 用于添加日志记录(有点像打印行),我使用 doOnEach()

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

2 - 你正在做的工作是你的流的一部分,你将来想要在流上做更多的工作 - 使用 map

apiResultStream
  .map(next -> {
        if (next) doSomeCallWithNextWhenTrue(next);
        else doSomeCallwithNextWhenFalse(next);
      })
  .subscribe(...
Run Code Online (Sandbox Code Playgroud)

3 - 如果这是您想要在管道结束时完成的工作 - 在完成所有转换或其他流工作之后的IE,则在订阅调用中执行此操作.

apiResultStream
  .subscribe(next -> {
            if (next) doSomeCallWithNextWhenTrue(next);
            else doSomeCallwithNextWhenFalse(next);
          });
Run Code Online (Sandbox Code Playgroud)

问题是 - 用这么简单的用例,很难建议最好的选择,但我很欣赏在学习Rx时,弄清楚如何做条件语句似乎令人困惑.一般来说,我只是使用mapflatMap当我调用另一个返回Observable并在那里执行逻辑的方法时.

更新

仍然不确定为什么你要拆分你的溪流.除非你开始使用不同的线程聪明,否则第一个订阅调用将阻止第二个调用,这可能不是你想要的.此外,如果您不多次拨打订阅,则不需要cache()呼叫.

if statementmap/ flatmap/中使用内容没有任何问题subscribe.特别是如果它使您的代码更具可读性.

我会做以下事情:

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

太干净了.

System.out.println订阅的电话我有点困惑.这是用于调试还是记录目的?如果是这样,只需在if语句中的上述flatMap中执行此操作.

希望这可以帮助,