Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Reactive Programming with RxJava

Slide 3

Slide 3 text

RxJava I’m Hugo Cordier CTO at Melusyn ◦ Java developer ◦ Groovy developer ◦ Javascript developer

Slide 4

Slide 4 text

“Melusyn helps film makers to manage and organize their productions” We are hiring! Drop me a line at [email protected]

Slide 5

Slide 5 text

You should download the examples I’ll use! github.com/Melusyn/ReactiveX-examples

Slide 6

Slide 6 text

RxJava ◦ Callbacks and Futures ◦ Where is Rx from? ◦ Introducing Observable ◦ Subscribing to an Observable ◦ Applying operators ◦ Handling errors ◦ Hot and Cold Observable ◦ Backpressure ◦ Schedulers

Slide 7

Slide 7 text

Callbacks and Futures

Slide 8

Slide 8 text

Rx - Callbacks server.listen(8080, "127.0.0.1", new AsyncResultHandler() { public void handle(AsyncResult asyncResult) { log.info("Listen succeeded?"+asyncResult.succeeded()); } } ); Lot of boilerplate code Hard to read A mess to chain

Slide 9

Slide 9 text

Rx - CompletableFutures CompletableFuture customerFuture = loadCustomerDetails(123); CompletableFuture shopFuture = closestShop(); CompletableFuture routeFuture = customerFuture.thenCombine(shopFuture, (cust, shop) -> findRoute(cust, shop) ); Easier to chain Easier to read But...

Slide 10

Slide 10 text

Futures contains only 1 value We can’t deal about time It’s hard to deal with threads

Slide 11

Slide 11 text

Where is Rx from?

Slide 12

Slide 12 text

Rx - Where’s it from ◦ Erik Meijer developed the concepts at Microsoft ◦ Microsoft open sourced Rx.NET and RxJS in 2012 ◦ In 2013 Netflix open sourced RxJava, based on Erik Meijer concepts

Slide 13

Slide 13 text

Introducing Observable

Slide 14

Slide 14 text

Observable - Iterable parallel Single return value Mutiple return values Synchronous Data getData() Iterable getData() Asynchronous Future getData() Observable getData()

Slide 15

Slide 15 text

Observable - Iterable parallel Data data = getData() if (data.equals(x)) { // Do something } else { // Do something else } Single return value Mutiple return values Synchronous Data getData() Iterable getData() Asynchronous Future getData() Observable getData()

Slide 16

Slide 16 text

Observable - Iterable parallel Iterable data = getData() data.forEach(value -> { if (value.equals(x)) { // Do something } else { // Do something else } }) Single return value Mutiple return values Synchronous Data getData() Iterable getData() Asynchronous Future getData() Observable getData()

Slide 17

Slide 17 text

Observable - Iterable parallel CompletableFuture data = getData() data.thenApply(value -> { if (value.equals(x)) { // Do something } else { // Do something else } }) Single return value Mutiple return values Synchronous Data getData() Iterable getData() Asynchronous Future getData() Observable getData()

Slide 18

Slide 18 text

Observable - Iterable parallel Observable data = getData() data.map(value -> { if (value.equals(x)) { // Do something } else { // Do something else } }) Single return value Mutiple return values Synchronous Data getData() Iterable getData() Asynchronous Future getData() Observable getData()

Slide 19

Slide 19 text

An Observable can : ● emit events (0 to ∞) ● emit an error ● complete stream Once an error has been emitted, no further events can be. An Observable could be infinite. Observable - Introduction

Slide 20

Slide 20 text

rx.Observable.create { observer -> try{ for (int i = 0; i < 2; i++) { observer.onNext(i); } observer.onCompleted(); } catch (Exception e) { observer.onError(e); } }

Slide 21

Slide 21 text

rx.Observable.create { observer -> executor.execute(new Runnable() { def void run() { try { for (int i = 0; i < 10; i++) { observer.onNext(i); this.sleep(2000) } observer.onCompleted(); } catch (Exception e) { observer.onError(e); } } }) }

Slide 22

Slide 22 text

Subscribing to an Observable Consuming data

Slide 23

Slide 23 text

getData() .subscribe(new Subscriber() { @Override void onNext(Object o) { logger.info(o) } @Override void onError(Throwable e) { logger.error("Oops", e) } @Override void onCompleted() { logger.debug("Stream has completed") } })

Slide 24

Slide 24 text

getData() .subscribe( { next -> logger.info(o) }, { e -> logger.error("Oops", e)}, { logger.debug("Stream has completed")} )

Slide 25

Slide 25 text

Live examples https://github.com/Melusyn/ReactiveX-examples

Slide 26

Slide 26 text

Applying operators Transform the data

Slide 27

Slide 27 text

This is a Marble Diagram Live examples : http://rxmarbles.com/#filter getData().filter {it >= 0}

Slide 28

Slide 28 text

rx.Observable.merge(getDataA(), getDataB()) .subscribe {value -> logger.info value} Live example : http://rxmarbles.com/#merge

Slide 29

Slide 29 text

rx.Observable.zip(getDataA(), getDataB(), {vA, vB -> [vA, vB] }) .subscribe {value -> logger.info value} Live example : http://rxmarbles.com/#zip

Slide 30

Slide 30 text

Observable getDataA(Integer param) {...} rx.Observable.range(1, 10) .flatMap(i -> getDataA(i)) .subscribe {String s -> logger.info s}

Slide 31

Slide 31 text

Live examples https://github.com/Melusyn/ReactiveX-examples

Slide 32

Slide 32 text

Let’s use swapi.co, the Star Wars API Films, Characters, Planets, Species, everything from Star Wars :D What if I want to fetch every Character of a film, consolidated with its homeworld planet and species? Let’s try with Rx! Real life exemple

Slide 33

Slide 33 text

Handling errors Oops! What should I do?

Slide 34

Slide 34 text

getData() .filter {it>3} .map {it+2} .subscribe( { next -> logger.info(o) }, { e -> logger.error("Oops", e) // Handle any error here }, { logger.debug("Stream has completed")} ) Once Observable has failed, it terminates and do not send any more events.

Slide 35

Slide 35 text

Errors can be caught with Observable onErrorResumeNext (Observable resumeSequence) Observable onErrorReturn (Func1 resumeFunction)

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Live examples https://github.com/Melusyn/ReactiveX-examples

Slide 39

Slide 39 text

Hot and Cold Observable behaviour

Slide 40

Slide 40 text

Cold Observables They are passive streams, producing events when subscribed to. This is default behaviour. def source = rx.Observable .interval(1, java.util.concurrent.TimeUnit. SECONDS) .doOnEach {println "Emitted an event"} source.subscribe ( {println it}, {it.printStackTrace()} ) This part is declarative. No events are emitted until something subscribe to it At this point, source starts to emit events

Slide 41

Slide 41 text

Hot Observables They are active streams, and produce events regardless of subscription def source = rx.Observable .interval(1, java.util.concurrent.TimeUnit.SECONDS) .doOnEach {println "Emitted an event"} .publish() source.connect() source.subscribe ( {println it}, {it.printStackTrace()} ) publish() makes it a hot observable which will be triggered by connect() At this point, source starts to emit events

Slide 42

Slide 42 text

Live examples https://github.com/Melusyn/ReactiveX-examples

Slide 43

Slide 43 text

Backpressure Controlling a stream from its subscriber

Slide 44

Slide 44 text

Backpressure As Hot Observables emit events as their own pace, what if it emits faster than subscriber can consume data? Backpressure allows subscriber to control the stream. Some existing operators implements backpressure : merge, zip, from, groupBy, delay, scan, ... It can be implemented in any Observable source.

Slide 45

Slide 45 text

Live examples https://github.com/Melusyn/ReactiveX-examples

Slide 46

Slide 46 text

Schedulers Where to run the source and operators?

Slide 47

Slide 47 text

Schedulers Rx is single threaded by default Schedulers define where to run each computation Each Operator has a default Scheduler [1] Rx allows developers to specify where to run their code using : public final Observable subscribeOn(Scheduler scheduler) public final Observable observeOn(Scheduler scheduler) [1] And you can find them here

Slide 48

Slide 48 text

Schedulers Scheduler Purpose Schedulers.computation(  ) meant for computational work such as event- loops and callback processing; do not use this scheduler for I/O (use Schedulers.io(  ) instead) Schedulers.from(executor) uses the specified Executor as a Scheduler Schedulers.immediate(  ) schedules work to begin immediately in the current thread Schedulers.io(  ) meant for I/O-bound work such as asynchronous performance of blocking I/O, this scheduler is backed by a thread-pool that will grow as needed; for ordinary computational work, switch to Schedulers.computation(  ) Schedulers.newThread(  ) creates a new thread for each unit of work Schedulers.trampoline(  ) queues work to begin on the current thread after any already-queued work

Slide 49

Slide 49 text

Live examples https://github.com/Melusyn/ReactiveX-examples

Slide 50

Slide 50 text

Going further Reactive programming world

Slide 51

Slide 51 text

Rx World ● Rx.NET ● RxJava, RxScala, RxGroovy, RxJRuby, RxNetty, RxAndroid ● Rx.rb ● Rx.py ● RxClojure ● RxCpp ● RxKotlin

Slide 52

Slide 52 text

Thanks! ANY QUESTIONS? You can find me at @HugoCrd [email protected]

Slide 53

Slide 53 text

No content