Wednesday, February 22, 2017

... about the perils of using the 'first' operator in rxJava

RxJava is a wonderful tool to do computation logic and stream processing. However, it sometimes behaves in unexpected ways. One of these will be discussed below:


first and single operator

According to the javadoc, first turns an observable into one that only returns 1 element and then terminates.

There's a similar operator called single. The difference is that the latter expects the source observable to only emit 1 item:
So, use first when you don't care how many items the source observable will emit. Otherwise use single.

When abstractions leak

However, they behave different when you add doOnCompleted, doOnTerminate and doAfterTerminate to the mix. These operators allow you to do some side effects after the last item has been emitted.

The following code will print "onCompleted called":
   Observable.just(1)
        .doOnCompleted(() -> System.out.println("onCompleted called") )
        .single()
        .subscribe()


The next code won't:
   Observable.just(1)
        .doOnCompleted(() -> System.out.println("onCompleted called") )
        .first()
        .subscribe()


The next example will:
   Observable.just(1)
        .first()
        .doOnCompleted(() -> System.out.println("onCompleted called") )
        .subscribe()


So, you will get different behavior depending on where you put doOnCompleted and if you use single or first.

The reason why first behaves unexpectedly is because it unsubscribes from the source observable ones it receives the first element. As a consequence the source observable never has the opportunity to signal completion. As a result, an upstream doOnCompleted handler is never called while a downstream doOnCompleted handler is.

By contrast, single will wait until it receives the completion signal from the source observable allowing upstream doOnCompleted handlers to be called.

Greetings
Jan

No comments:

Post a Comment