Difference between first() and take(1)

Paul Woitaschek picture Paul Woitaschek · Jan 26, 2016 · Viewed 11.3k times · Source

I am trying to understand the details of RxJava.

Intuitively I expected first() and take(1) to be equal and do the same. However by digging in the source code first() is defined as take(1).single().

What is the single() here good for? Doesn't take(1) already guarantee to output a single item?

Answer

akarnokd picture akarnokd · Jan 27, 2016

The difference is that take(1) will relay 0..1 items from upstream whereas first will relay the very first element or emits an error (NoSuchElementException) if the upstream is empty. Neither of them is blocking.

It is true first == take(1).single() where take(1) limits the number of upstream items to 1 and single() makes sure upstream isn't empty.

This example prints "Done" only

Observable.empty().take(1)
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example prints "1" followed by "Done":

Observable.just(1).take(1)
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example also prints "1" followed by "Done":

Observable.just(1, 2, 3).take(1)
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example fails with NoSuchElementException

Observable.empty().first()
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example, again, prints "1" followed by "Done":

Observable.just(1).first()
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example, again, prints "1" followed by "Done":

Observable.just(1, 2, 3).first()
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example prints a stacktrace of NoSuchElementException because the source contained too few elements:

Observable.empty().single()
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));

This example prints a stacktrace of IllegalArgumentException because the source contained too many elements:

Observable.just(1, 2, 3).single()
.subscribe(System.out::println, 
    Throwable::printStackTrace, 
    () -> System.out.println("Done"));