Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJava, RxJava 2, Reactor : Etat de l’art des Reactive Streams en Java

David
April 06, 2017

RxJava, RxJava 2, Reactor : Etat de l’art des Reactive Streams en Java

2017 sera l’année des Reactive Streams en Java : RxJava est largement utilisé sur Android ou côté backend à travers Hystrix. RxJava 2 vient tout juste de sortir et va pouvoir profiter du chemin déjà tracé par sa précédente version. Pivotal pousse Reactor qui sera disponible dans le framework Spring version 5.

Qu’apportes ces différentes implémentations, en terme d’API ou de performances ? En quoi sont-elles différentes ? Faut-il migrer sur RxJava 2 tout de suite ? Reactor va-t’il remplacer RxJava et se limite t'il au framework Spring ?

Cette conférence fera un bref historique des ces bibliothèques avant de faire une comparaison des APIs, performances et cas d’utilisation de ces Reactive Streams.

Devoxx France ( Paris ) - 6 Avril 2017

David

April 06, 2017
Tweet

More Decks by David

Other Decks in Programming

Transcript

  1. RxJava, RxJava 2, Reactor
    État de l’art des Reactive Streams sur la JVM

    View Slide

  2. David
    Wursteisen

    View Slide

  3. View Slide

  4. Écrire du code asynchrone : 

    ça craint

    View Slide

  5. Future
    ExecutorService ex = Executors.newCachedThreadPool();

    Future future = ex.submit(() -> longProcessing());

    String result = future.get();
    Appel bloquant

    View Slide

  6. Future
    Future> future1 = /* ... */

    Future> future2 = /* ... */

    Future> future3 = /* ... */

    Future> future4 = /* ... */

    Future> future5 = /* ... */
    Orchestration
    optimale ?

    View Slide

  7. Callback
    RemoteService service = buildRemoteService();

    service.getUser(id -> {

    service.getData(id, data -> {

    service.getSomething(data, whut -> {
    service.neverEndingCallBack(whut, () -> {
    });
    });

    });

    });
    Callback Hell

    View Slide

  8. Relationship Status:

    it’s complicated

    View Slide

  9. Le problème
    du code synchrone

    View Slide

  10. Synchrone
    Attente de la réponse
    Appelant
    Appelé

    View Slide

  11. Impacte le temps
    de réponse
    Serveur lent

    View Slide

  12. Il y a toujours
    un truc qui ne
    marche pas
    ça m’énerve !

    View Slide

  13. View Slide

  14. Ça ne
    marche pas !
    ça a planté ?
    dans le
    doute, reboot

    View Slide

  15. Asynchrone
    Appelant
    Appelé
    Traitement continu

    View Slide

  16. L’asynchrone permet de profiter
    du temps d’attente

    View Slide

  17. Impact minimum
    sur le temps de
    réponse

    View Slide

  18. View Slide

  19. Écrire du code asynchrone
    facilement ?

    View Slide

  20. Émergence 

    de différentes approches

    View Slide

  21. 2
    Reactive Streams

    View Slide

  22. Reactive Streams
    API Reactive Streams
    RxJava 2 Reactor
    Interface
    Implémentation

    View Slide

  23. L’API Reactive Streams est 

    un pont 

    entre les implémentations

    View Slide

  24. Contrat Reactive Streams
    onSubscribe onNext onError
    onComplete

    View Slide

  25. RxJava n’est
    pas compatible 

    avec Reactive Streams
    (il faut alors utiliser un adapteur : RxJavaReactiveStreams)
    https://github.com/ReactiveX/RxJavaReactiveStreams

    View Slide

  26. onNext * ( onError | onComplete )

    onNext * ( onError | onCompleted )
    RxJava
    Reactive Streams

    View Slide

  27. onNext * ( onError | onComplete )

    onNext * ( onError | onCompleted )
    RxJava
    Reactive Streams
    Nom différent

    View Slide

  28. Reactor
    peut utiliser
    RxJava 2
    et réciproquement

    View Slide

  29. Approche
    commune

    View Slide

  30. API pour manipuler 

    des événements de manière
    synchrone ou asynchrone
    à travers un flux d’événements

    View Slide

  31. View Slide

  32. Map ( ⃝ →
    ⬛)

    View Slide

  33. View Slide

  34. View Slide

  35. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);

    View Slide

  36. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);

    View Slide

  37. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Push du résultat

    View Slide

  38. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Récupération des
    véhicules de Luke
    Récupération des
    vaisseaux de Luke

    View Slide

  39. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Flux 

    d’événements
    Flux 

    d’événements

    View Slide

  40. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Fusion des 2 flux

    View Slide

  41. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Déclenche l’exécution du
    code

    View Slide

  42. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Flux 

    d’événements

    View Slide

  43. View Slide

  44. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) 

    .observeOn(Schedulers.io()) 

    .switchMap(evt -> remoteApi.getData())

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();

    View Slide

  45. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Écoute des clicks

    View Slide

  46. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Changement du
    contexte d’exécution

    View Slide

  47. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Appel asynchrone
    d’un web service

    View Slide

  48. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Changement du
    contexte d’exécution

    View Slide

  49. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Changement au niveau
    de l’UI

    View Slide

  50. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Flux 

    d’événements

    View Slide

  51. Button btn = new Button();

    btn.setText("Click Me");


    ExecutorService io = Executors.newSingleThreadExecutor();

    btn.setOnAction(evt -> {

    io.submit(() -> {

    remoteApi.getData(data -> {

    Platform.runLater(() -> {

    btn.setText(data);

    });

    });

    });

    });
    Sac de noeud
    Structure pyramidale

    View Slide

  52. Grâce à RxJava
    et Reactor

    View Slide

  53. Écrire du code asynchrone : 

    ça craint

    View Slide

  54. Il était une fois…

    View Slide

  55. Création des 

    Reactive Extensions
    Création de RxJava
    Participation active
    Reprise de 

    RxJava & RxJava 2
    Création de Reactor
    Participation à Reactor

    View Slide

  56. RxJava 

    est une technologie 

    éprouvée

    View Slide

  57. Reactor

    profite de l’expérience de 

    RxJava
    (et vice versa)

    View Slide

  58. Types d’objet

    View Slide

  59. Observable

    View Slide

  60. View Slide

  61. View Slide

  62. View Slide

  63. View Slide

  64. View Slide

  65. Single

    View Slide

  66. View Slide

  67. Completable

    View Slide

  68. View Slide

  69. RxJava
    Contrat Backpressure
    Observable [N] Oui
    Single [1] Non
    Completable [0] Non
    Ajouté après coup
    Appel Web
    service
    Processus
    d’arrière plan

    View Slide

  70. Écouter une websocket, pour
    c h a q u e c o m m a n d e r e ç u e ,
    composer une réponse à partir de
    3 webservices différents, puis
    exécuter 2 jobs séquentiellement ?

    View Slide

  71. Écouter une websocket, pour
    c h a q u e c o m m a n d e r e ç u e ,
    composer une réponse à partir de
    3 webservices différents, puis
    exécuter 2 jobs séquentiellement ?

    View Slide

  72. Écouter une websocket, pour
    c h a q u e c o m m a n d e r e ç u e ,
    composer une réponse à partir de
    3 webservices différents, puis
    exécuter 2 jobs séquentiellement ?

    View Slide

  73. Écouter une websocket, pour
    c h a q u e c o m m a n d e r e ç u e ,
    composer une réponse à partir de
    3 webservices différents, puis
    exécuter 2 jobs séquentiellement ?

    View Slide

  74. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));

    View Slide

  75. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Écoute de la websocket
    Observable

    View Slide

  76. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Composition d’une réponse à
    partir de 3 webservices
    Single

    View Slide

  77. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Completable
    Exécuter 2 jobs

    View Slide

  78. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Écoute de la websocket
    Observable Composition d’une réponse à
    partir de 3 webservices
    Single
    Completable
    Exécuter 2 jobs

    View Slide

  79. RxJava 2
    Contrat Backpressure
    Observable [N] Non
    Single [1] Non
    Completable [0] Non
    Maybe [0|1] Non Nouveau !
    Concept
    « similaire » à
    Optional

    View Slide

  80. Maybe

    View Slide

  81. View Slide

  82. Backpressure
    avec RxJava 2

    View Slide

  83. Consommateur

    View Slide

  84. Consommateur
    ça déborde !

    View Slide

  85. backpressure

    View Slide

  86. MissingBackpressureException ?

    View Slide

  87. acceptedIntent

    .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false))

    .concatMap(intent -> approximatedEngine.detectCurrentPlace())

    .doOnNext(score -> Log.info(TAG, "Scan completed with result " + score))

    .concatMap(this::detectSleepMode)

    .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))

    .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))

    .subscribe()

    View Slide

  88. acceptedIntent

    .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false))
    .onBackpressureDrop()

    .concatMap(intent -> approximatedEngine.detectCurrentPlace())

    .doOnNext(score -> Log.info(TAG, "Scan completed with result " + score))

    .onBackpressureDrop()
    .concatMap(this::detectSleepMode)

    .onBackpressureDrop()

    .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))

    .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))

    .subscribe()
    Ajouté dans un
    moment de
    panique

    View Slide

  89. RxJava 2
    Contrat Backpressure
    Observable [N] Non
    Single [1] Non
    Completable [0] Non
    Maybe [0|1] Non Nouveau !
    Concept
    « similaire » à
    Optional

    View Slide

  90. RxJava 2
    Contrat Backpressure
    Observable [N] Non
    Single [1] Non
    Completable [0] Non
    Maybe [0|1] Non
    Flowable [N] Oui
    Nouveau !
    Observable avec 

    back pressure
    Concept
    « similaire » à
    Optional

    View Slide

  91. Observable
    → moins de 1000 éléments
    → Gestion d’élément d’interface graphique
    → Remplacement de Stream Java
    Flowable
    → plus de 10 000 éléments
    → contrôle de l’émission de données
    → Flux réseau avec contrôle de débit

    View Slide

  92. Que propose
    Reactor ?

    View Slide

  93. Flux
    Mono
    Maximum 1 élément

    View Slide

  94. Reactor
    Contrat Backpressure
    Flux [N] Oui
    Mono [0|1] Oui
    Identique à
    Flowable
    Flux avec 

    au maximum 

    1 élément

    View Slide

  95. Types d’objets et

    Reactive Streams

    View Slide

  96. Publisher
    Flux Flowable
    Reactive Streams

    View Slide

  97. Flux.range(1, 10)

    .flatMap(i -> Flux.just(1))

    .subscribe();

    View Slide

  98. Flux.range(1, 10)

    .flatMap(i -> Flux.just(1))

    .subscribe();
    Publisher

    View Slide

  99. Flux.range(1, 10)

    .flatMap(i -> Flowable.just(1))

    .subscribe();
    Publisher
    RxJava 2

    View Slide

  100. Flowable.defer(() -> Flux.range(1, 10))

    .subscribe(System.out::println);
    RxJava 2 Reactor

    View Slide

  101. Flux.defer(() -> Flowable.range(1, 10))

    .subscribe(System.out::println);
    RxJava 2
    Reactor

    View Slide

  102. Encore plus de possibilités
    avec reactor-addons
    https://github.com/reactor/reactor-addons

    View Slide

  103. Observable.range(1, 10)

    .to(obs -> RxJava2Adapter.observableToFlux(obs, BackpressureStrategy.BUFFER))

    .checkpoint()

    .subscribe();
    Maybe.empty()

    .to(maybe -> RxJava2Adapter.maybeToMono(maybe))

    .checkpoint()

    .subscribe();
    Single.just(1)

    .to(single -> RxJava2Adapter.singleToMono(single))

    .checkpoint()

    .subscribe();
    Observable → Flux
    Single → Mono
    Maybe → Mono

    View Slide

  104. RxJava2Adapter.monoToFlowable(Mono.just(1))

    .timestamp()

    .subscribe();


    RxJava2Adapter.fluxToFlowable(Flux.range(1, 10))

    .timestamp()

    .subscribe();
    Mono → Flowable
    Flux → Flowable

    View Slide

  105. P o u v o i r u t i l i s e r u n e
    biblio t hèq ue utilisant
    RxJava 2 dans son projet
    Reactor
    (et vice versa)

    View Slide

  106. Opérateurs

    View Slide

  107. Catalogue
    conséquent et homogène

    View Slide

  108. all amb ambArray ambWith any as awaitOnSubscribe blockFirst blockFirstMillis blockLast blockLastMillis
    blockingFirst blockingForEach blockingIterable blockingLast blockingLatest blockingMostRecent blockingNext
    blockingSingle blockingSubscribe buffer bufferMillis bufferSize bufferTimeout bufferTimeoutMillis bufferUntil
    bufferWhile cache cacheWithInitialCapacity cancelOn cast checkpoint collect collectInto collectList collectMap
    collectMultimap collectSortedList combineLatest combineLatestDelayError compose concat concatArray
    concatArrayDelayError concatArrayEager concatDelayError concatEager concatMap concatMapDelayError
    concatMapEager concatMapEagerDelayError concatMapIterable concatWith contains count create debounce
    defaultIfEmpty defer delay delayElements delayElementsMillis delayMillis delaySubscription delaySubscriptionMillis
    dematerialize distinct distinctUntilChanged doAfterNext doAfterTerminate doFinally doOnCancel doOnComplete
    doOnEach doOnError doOnLifecycle doOnNext doOnRequest doOnSubscribe doOnTerminate elapsed elementAt
    elementAtOrError empty equals error filter first firstElement firstEmitting firstEmittingWith firstOrError flatMap
    flatMapCompletable flatMapIterable flatMapMaybe flatMapSequential flatMapSingle forEach forEachWhile from
    fromArray fromCallable fromFuture fromIterable fromPublisher fromStream generate getClass getPrefetch groupBy
    groupJoin handle hasElement hasElements hashCode hide ignoreElements interval intervalMillis intervalRange
    isEmpty join just last lastElement lastOrError lift limitRate log map mapError materialize merge mergeArray
    mergeArrayDelayError mergeDelayError mergeSequential mergeWith never next notify notifyAll observeOn ofType
    onBackpressureBuffer onBackpressureDrop onBackpressureError onBackpressureLatest onErrorResumeNext
    onErrorResumeWith onErrorReturn onErrorReturnItem onExceptionResumeNext onTerminateDetach parallel publish
    publishNext publishOn range rangeLong rebatchRequests reduce reduceWith repeat repeatUntil repeatWhen
    replay replayMillis retry retryUntil retryWhen safeSubscribe sample sampleFirst sampleFirstMillis sampleMillis
    sampleTimeout scan scanWith sequenceEqual serialize share single singleElement singleOrEmpty singleOrError
    skip skipLast skipMillis skipUntil skipUntilOther skipWhile sort sorted startWith startWithArray strict subscribe
    subscribeOn subscribeWith switchIfEmpty switchMap switchMapDelayError switchOnError switchOnNext
    switchOnNextDelayError take takeLast takeMillis takeUntil takeUntilOther takeWhile test then thenEmpty thenMany
    throttleFirst throttleLast throttleWithTimeout timeInterval timeout timeoutMillis timer timestamp to toFuture toIterable
    toList toMap toMultimap toObservable toSortedList toStream toString transform unsafeCreate unsubscribeOn using
    wait window windowMillis windowTimeout windowTimeoutMillis windowUntil windowWhile withLatestFrom zip
    zipArray zipIterable zipWith zipWithIterable

    View Slide

  109. RxJava RxJava 2 Reactor
    flatMap flatMap flatMap
    Émission d’aucune,
    une ou plusieurs
    valeurs
    amb amb firstEmitting
    Émission des valeurs
    du flux répondant en
    premier
    … … … …
    debounce debounce N/A
    Ignore les
    événements pendant
    un laps de temps

    View Slide

  110. RxJava RxJava 2 Reactor
    flatMap flatMap flatMap
    Émission d’aucune,
    une ou plusieurs
    valeurs
    amb amb firstEmitting
    Émission des valeurs
    du flux répondant en
    premier
    … … … …
    debounce debounce N/A
    Ignore les
    événements pendant
    un laps de temps
    Renommage

    View Slide

  111. L’ensemble des opérateurs
    couvre
    de nombreuses situations

    View Slide

  112. Nota bene

    View Slide

  113. https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft)
    writing operators is hard
    when one writes an operator, the Observable
    protocol, unsubscription, backpressure and
    concurrency have to be taken into account and
    adhered to the letter

    View Slide

  114. Écrire un opérateur avec RxJava 2 est
    plus complexe
    qu’avec RxJava

    View Slide

  115. Rendre son application
    Reactive

    View Slide

  116. -Jake Wharton
    « Unless you can model your entire system
    synchronously, a single asynchronous source
    breaks imperative programming »

    View Slide

  117. -Jake Wharton
    « Unless you can model your entire system
    synchronously, a single asynchronous source
    breaks imperative programming »

    View Slide

  118. Reactive
    Reactive
    API Synchrone
    Callback
    Reactive
    Reactive

    View Slide

  119. Utilisation de
    Factory

    View Slide

  120. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just
    Émission d’une valeur
    existante
    Flowable.defer Flux.defer
    Émission tardive d’un
    Observable
    Flowable.fromCallable Mono.fromCallable
    Émission à partir d’un appel
    de fonction
    Flowable.create Flux.create
    Contrôle manuel de l’émission
    des événements
    Flowable.using Flux.using Gestion d’une ressource
    Flowable.fromPublisher Flux.from
    Utilisation d’un Publisher
    (Reactive Streams)
    Flowable.generate Flux.generate
    Utilisation d’un générateur de
    valeurs

    View Slide

  121. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just
    Émission d’une valeur
    existante
    Flowable.defer Flux.defer
    Émission tardive d’un
    Observable
    Flowable.fromCallable Mono.fromCallable
    Émission à partir d’un appel
    de fonction
    Flowable.create Flux.create
    Contrôle manuel de l’émission
    des événements
    Flowable.using Flux.using Gestion d’une ressource
    Flowable.fromPublisher Flux.from
    Utilisation d’un Publisher
    (Reactive Streams)
    Flowable.generate Flux.generate
    Utilisation d’un générateur de
    valeurs

    View Slide

  122. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just
    Émission d’une valeur
    existante
    Flowable.defer Flux.defer
    Émission tardive d’un
    Observable
    Flowable.fromCallable Mono.fromCallable
    Émission à partir d’un appel
    de fonction
    Flowable.create Flux.create
    Contrôle manuel de l’émission
    des événements
    Flowable.using Flux.using Gestion d’une ressource
    Flowable.fromPublisher Flux.from
    Utilisation d’un Publisher
    (Reactive Streams)
    Flowable.generate Flux.generate
    Utilisation d’un générateur de
    valeurs

    View Slide

  123. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just
    Émission d’une valeur
    existante
    Flowable.defer Flux.defer
    Émission tardive d’un
    Observable
    Flowable.fromCallable Mono.fromCallable
    Émission à partir d’un appel
    de fonction
    Flowable.create Flux.create
    Contrôle manuel de l’émission
    des événements
    Flowable.using Flux.using Gestion d’une ressource
    Flowable.fromPublisher Flux.from
    Utilisation d’un Publisher
    (Reactive Streams)
    Flowable.generate Flux.generate
    Utilisation d’un générateur de
    valeurs

    View Slide

  124. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just
    Émission d’une valeur
    existante
    Flowable.defer Flux.defer
    Émission tardive d’un
    Observable
    Flowable.fromCallable Mono.fromCallable
    Émission à partir d’un appel
    de fonction
    Flowable.create Flux.create
    Contrôle manuel de l’émission
    des événements
    Flowable.using Flux.using Gestion d’une ressource
    Flowable.fromPublisher Flux.from
    Utilisation d’un Publisher
    (Reactive Streams)
    Flowable.generate Flux.generate
    Utilisation d’un générateur de
    valeurs

    View Slide

  125. exemple
    d’encapsulation

    View Slide

  126. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }

    View Slide

  127. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }
    Écoute de Redis

    View Slide

  128. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }
    Code de synchronisation
    Code de synchronisation

    View Slide

  129. Étape 1
    Encapsuler

    View Slide

  130. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {


    String result = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .blockingFirst();

    return result;

    }
    }

    View Slide

  131. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {


    String result = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .blockingFirst();

    return result;

    }
    }
    Encapsulation
    Synchronisation
    Contract Reactive

    View Slide

  132. Étape 2
    Asynchrone

    View Slide

  133. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private DeferredResult redis() throws InterruptedException {


    DeferredResult result = new DeferredResult<>(10_000l);


    Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .subscribe(result::setResult);


    return result;

    }

    View Slide

  134. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private DeferredResult redis() throws InterruptedException {


    DeferredResult result = new DeferredResult<>(10_000l);


    Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .subscribe(result::setResult);


    return result;

    } Résultat tardif
    Utilisation de DeferredResult

    View Slide

  135. Étape 3
    Reactive Streams

    View Slide

  136. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Flux redis() throws InterruptedException {


    Flowable rxjava = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    return Flux.defer(() -> rxjava);

    }
    }

    View Slide

  137. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Flux redis() throws InterruptedException {


    Flowable rxjava = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    return Flux.defer(() -> rxjava);

    }
    }
    RxJava 2 → Flux
    Flux → SSE

    View Slide

  138. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Publisher redis() throws InterruptedException {

    return Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    }

    View Slide

  139. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Publisher redis() throws InterruptedException {

    return Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    }
    Publisher

    View Slide

  140. View Slide

  141. Migrer son application
    Reactive
    depuis RxJava

    View Slide

  142. rx.Observable io.reactivex.Observable
    rx.Single
    rx.Completable io.reactivex.Completable
    io.reactivex.Single
    RxJava RxJava 2
    package différent

    View Slide

  143. RxJavaInterop.toV2Observable(rx.Observable.just(1, 2, 3))

    .firstElement()

    .subscribe();


    RxJavaInterop.toV1Observable(io.reactivex.Observable.just(1, 2, 3), 

    BackpressureStrategy.DROP)

    .first()

    .subscribe();
    https://github.com/akarnokd/RxJava2Interop
    RxJava → RxJava 2
    RxJava 2 → RxJava

    View Slide

  144. Reactive Streams
    n’ acceptent pas
    de valeur null
    (sauf Maybe.fromCallable)

    View Slide

  145. Observable.just(null);


    Single.just(null);


    Observable.fromCallable(() -> null)

    .subscribe(System.out::println, Throwable::printStackTrace);


    Observable.just(1).map(v -> null)

    .subscribe(System.out::println, Throwable::printStackTrace);
    NullPointerException
    NullPointerException
    NullPointerException
    N
    ullPointerException

    View Slide

  146. Reactor se base sur
    Java 8 tandis que
    RxJava 2 utilise Java 6

    View Slide

  147. Reactor se base sur
    Java 8 tandis que
    RxJava 2 utilise Java 6

    View Slide

  148. Flux.interval(Duration.of(1, ChronoUnit.SECONDS))

    .map(i -> String.valueOf(i))

    .subscribe();

    View Slide

  149. Flux.interval(Duration.of(1, ChronoUnit.SECONDS))

    .map(i -> String.valueOf(i))

    .subscribe();
    java.time.Duration
    java.util.Function

    View Slide

  150. Flux.fromStream(stream)

    .map(i -> "value -> " + String.valueOf(i))

    .toStream()

    .forEach(System.out::println);

    View Slide

  151. Flux.fromStream(stream)

    .map(i -> "value -> " + String.valueOf(i))

    .toStream()

    .forEach(System.out::println);
    Conversion Stream Java 8 en Flux
    Conversion Flux en Stream Java 8

    View Slide

  152. Reactor se base sur
    Java 8 tandis que
    RxJava 2 utilise Java 6

    View Slide

  153. Reactor se base sur
    Java 8 tandis que
    RxJava 2 utilise Java 6

    View Slide

  154. rx.Action1
    rx.Func1
    RxJava RxJava 2
    rx.Func2
    rx.Func3
    rx.Action2
    io.reactivex.functions.Consumer
    io.reactivex.functions.Function
    io.reactivex.functions.BiFunction
    io.reactivex.functions.Function3
    io.reactivex.functions.BiConsumer
    Suivre les conventions Java 8

    View Slide

  155. Observable.interval(1, TimeUnit.SECONDS)

    .map(i -> String.valueOf(i))

    .subscribe();

    View Slide

  156. Observable.interval(1, TimeUnit.SECONDS)

    .map(i -> String.valueOf(i))

    .subscribe();
    java.util.concurrent.TimeUnit

    View Slide

  157. Observable.interval(1, TimeUnit.SECONDS)

    .map(i -> String.valueOf(i))

    .subscribe();
    io.reactivex.functions.Function

    View Slide

  158. Asynchrone
    gestion de contexte d’exécution

    View Slide

  159. Schedulers
    Rethink cette partie là

    View Slide

  160. Scheduler 

    (Pool de Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  161. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  162. Tâche 1 Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  163. Tâche 1 Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  164. Tâche 1 Tâche 2
    Tâche 3 Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  165. Tâche 1
    Tâche 2
    Tâche 3 Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  166. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  167. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  168. Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4
    Scheduler 

    (Pool de Thread)

    View Slide

  169. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  170. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  171. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  172. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  173. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  174. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  175. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  176. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  177. Scheduler 

    (Single Thread)
    Tâche 1
    Tâche 2
    Tâche 3
    Tâche 4

    View Slide

  178. java.lang.IllegalStateException: 

    Not on the main thread
    NetworkOnMainThreadException

    View Slide

  179. JavaFx.fromClick(btn) 

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(Schedulers.computation())

    .flatMap(data -> intensiveComputation(data))

    .observeOn(javaFx())

    .doOnNext(value -> btn.setText("Data: " + value)) 

    .subscribe();

    View Slide

  180. JavaFx.fromClick(btn) 

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(Schedulers.computation())

    .flatMap(data -> intensiveComputation(data))

    .observeOn(javaFx())

    .doOnNext(value -> btn.setText("Data: " + value)) 

    .subscribe();
    entrée/sortie
    calculs
    Thread graphique

    View Slide

  181. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Pool de Thread qui
    grossit au besoin
    computation() computation() parallel() Pool fini de Thread
    single() single() single() Pool de 1 Thread
    immediate() immediate()
    Execute la tâche
    immédiatement
    trampoline() trampoline()
    Ajoute la tâche dans
    une file d’attente
    avant de l’executer

    View Slide

  182. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Pool de Thread qui
    grossit au besoin
    computation() computation() parallel() Pool fini de Thread
    single() single() single() Pool de 1 Thread
    immediate() immediate()
    Execute la tâche
    immédiatement
    trampoline() trampoline()
    Ajoute la tâche dans
    une file d’attente
    avant de l’executer

    View Slide

  183. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Pool de Thread qui
    grossit au besoin
    computation() computation() parallel() Pool fini de Thread
    single() single() single() Pool de 1 Thread
    immediate() immediate()
    Execute la tâche
    immédiatement
    trampoline() trampoline()
    Ajoute la tâche dans
    une file d’attente
    avant de l’executer

    View Slide

  184. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Pool de Thread qui
    grossit au besoin
    computation() computation() parallel() Pool fini de Thread
    single() single() single() Pool de 1 Thread
    immediate() immediate()
    Execute la tâche
    immédiatement
    trampoline() trampoline()
    Ajoute la tâche dans
    une file d’attente
    avant de l’executer

    View Slide

  185. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Pool de Thread qui
    grossit au besoin
    computation() computation() parallel() Pool fini de Thread
    single() single() single() Pool de 1 Thread
    immediate() immediate()
    Execute la tâche
    immédiatement
    trampoline() trampoline()
    Ajoute la tâche dans
    une file d’attente
    avant de l’executer
    Absent pour votre
    bien

    View Slide

  186. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Pool de Thread qui
    grossit au besoin
    computation() computation() parallel() Pool fini de Thread
    single() single() single() Pool de 1 Thread
    immediate() immediate()
    Execute la tâche
    immédiatement
    trampoline() trampoline()
    Ajoute la tâche dans
    une file d’attente
    avant de l’executer

    View Slide

  187. Reactor
    nommage technique

    View Slide

  188. RxJava
    nommage fonctionnel

    View Slide

  189. Backpressure

    View Slide

  190. Consommateur
    ça déborde !

    View Slide

  191. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


    private Subscription source;


    @Override

    public void onSubscribe(Subscription s) {

    this.source = s;

    this.source.request(1);

    }


    @Override

    public void onNext(Integer o) {

    longComputation(o);

    this.source.request(1);

    }

    });

    View Slide

  192. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


    private Subscription source;


    @Override

    public void onSubscribe(Subscription s) {

    this.source = s;

    this.source.request(1);

    }


    @Override

    public void onNext(Integer o) {

    longComputation(o);

    this.source.request(1);

    }

    });
    Garder la référence de
    l’abonnement
    Demander l’émission des
    éléments suivants
    Demande l’émission
    des premiers
    éléments

    View Slide

  193. Flowable.range(1, 100000)

    .subscribe(new Subscriber() {


    private Subscription source;


    @Override

    public void onSubscribe(Subscription s) {

    this.source = s;

    this.source.request(1);

    }


    @Override

    public void onNext(Integer o) {

    longComputation(o);

    this.source.request(1);

    }

    });
    Contrôle de l’émission

    View Slide

  194. source()

    .subscribe(new Subscriber() {


    private Subscription source;


    @Override

    public void onSubscribe(Subscription s) {

    this.source = s;

    this.source.request(1);

    }


    @Override

    public void onNext(Integer o) {

    longComputation(o);

    this.source.request(1);

    }

    });
    Kafka JDBC
    Fichier

    View Slide

  195. La mécanique est
    identique
    avec Reactor
    (merci les Reactive Streams)

    View Slide

  196. Debug
    Rajouter stack insignifiant

    View Slide

  197. rx.exceptions.OnErrorNotImplementedException: Sequence contains too many elements
    at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:
    386)
    at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:
    383)
    at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44)
    at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153)
    at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115)
    at rx.internal.operators.OperatorSingle$ParentSubscriber.onNext(OperatorSingle.java:97)
    at rx.internal.operators.OnSubscribeRange$RangeProducer.slowPath(OnSubscribeRange.java:90)
    at rx.internal.operators.OnSubscribeRange$RangeProducer.request(OnSubscribeRange.java:68)
    at rx.Subscriber.setProducer(Subscriber.java:211)
    at rx.internal.operators.OnSubscribeRange.call(OnSubscribeRange.java:38)
    Stacktrace inexploitable

    View Slide

  198. RxJavaHooks.enableAssemblyTracking();
    […]
    Caused by: rx.exceptions.AssemblyStackTraceException: Assembly trace:
    at rx.Observable.create(Observable.java:100)
    at rx.Observable.lift(Observable.java:237)
    at rx.Observable.single(Observable.java:9330)
    at rxjava2.BasicExampleTest.stacktrace(BasicExampleTest.java:225)
    rx.Observable.range(1, 100)

    .single()

    .subscribe();

    View Slide

  199. enableTracing n’est
    pas encore supporté
    par RxJava 2
    (pour cela, il faut utiliser RxJava2Extensions)
    https://github.com/akarnokd/RxJava2Extensions

    View Slide

  200. Hooks.onOperator(providedHook -> providedHook.operatorStacktrace());


    Flux.just(1, 2, 3)

    .single()

    .subscribe(System.out::println, Throwable::printStackTrace);

    View Slide

  201. Hooks.onOperator(providedHook -> providedHook.operatorStacktrace());


    Flux.just(1, 2, 3)

    .single()

    .subscribe(System.out::println, Throwable::printStackTrace);

    View Slide

  202. Flux.range(1, 100)

    .single()

    .checkpoint("label")

    .subscribe(…);

    View Slide

  203. Flux.range(1, 100)

    .single()

    .checkpoint("label")

    .subscribe(…);

    View Slide

  204. Flux.range(1, 100)

    .single()

    .checkpoint("label")

    .subscribe(…);
    Assembly trace from producer [reactor.core.publisher.MonoSingle], described as [label] :
    reactor.core.publisher.Mono.checkpoint(Mono.java:1304)
    rxjava2.BasicExampleTest.stacktraceReactor(BasicExampleTest.java:236)
    Error has been observed by the following operator(s):
    |_ Mono.checkpoint(BasicExampleTest.java:236)

    View Slide

  205. Attention
    dégradation des
    performances !

    View Slide

  206. Performance

    View Slide

  207. Génération
    3 4 5+
    Fusion
    RxJava 2
    Reactor

    View Slide

  208. Attention
    Slides conceptuels

    View Slide

  209. Sans fusion

    View Slide

  210. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  211. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  212. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  213. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  214. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  215. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  216. Avec fusion

    View Slide

  217. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  218. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  219. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  220. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  221. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  222. La fusion
    diminue
    la consommation mémoire et
    augmente
    les performances

    View Slide

  223. for (int x = 0; x < 10_000; x++) {


    Observable.interval(10, TimeUnit.MILLISECONDS)

    .takeWhile(i -> take.get())

    .flatMap(i -> Observable.range(1, 100))

    .subscribe();

    }

    View Slide

  224. RxJava 2 RxJava
    Reactor

    View Slide

  225. http://akarnokd.blogspot.fr/2016/12/the-reactive-scrabble-benchmarks.html
    Stream Java 8
    RxJava 2 / Reactor
    RxJava
    Décembre 2016

    View Slide

  226. Stream Java 8
    RxJava 2 / Reactor
    RxJava
    https://twitter.com/akarnokd/status/844555409012740096
    Mars 2017

    View Slide

  227. RxJava 2 : 

    streams performants
    pour Android

    View Slide

  228. Reactor & RxJava 2 : 

    streams performants
    pour serveur web

    View Slide

  229. Ecosystème

    View Slide

  230. Communauté Sponsor
    RxJava Grande
    Anciennement Netflix

    Maintenant Community
    RxJava 2 Grande Community
    Reactor En croissance Pivotal

    View Slide

  231. RxJava RxJava 2 Reactor
    Retrofit Oui Oui Non
    RxAndroid Oui Oui Non
    Realm Oui Non Non
    Hystrix Oui Non Non
    Couchbase Oui Non Non
    MongoDB Oui Non Non
    Spring Data 2.0 Oui Non Oui
    Reactor IPC Non Non Oui
    WebFlux Non Oui Oui
    Android Spring

    View Slide

  232. RxJava RxJava 2 Reactor
    Retrofit Oui Oui Non
    RxAndroid Oui Oui Non
    Realm Oui Non Non
    Hystrix Oui Non Non
    Couchbase Oui Non Non
    MongoDB Oui Non Non
    Spring Data 2.0 Oui Non Oui
    Reactor IPC Non Non Oui
    WebFlux Non Oui Oui
    Android Spring

    View Slide

  233. We are aggressively 

    migrating our internal code to
    RxJava 2
    https://github.com/uber/AutoDispose

    View Slide

  234. RxJava RxJava 2 Reactor
    Retrofit Oui Oui Non
    RxAndroid Oui Oui Non
    Realm Oui Non Non
    Hystrix Oui Non Non
    Couchbase Oui Non Non
    MongoDB Oui Non Non
    Spring Data 2.0 Oui Non Oui
    Reactor IPC Non Non Oui
    WebFlux Non Oui Oui
    Android Spring
    genre pourquoi si tu as une stack spring se forcer a faire
    du rx2 si le support reactor est meilleur)?

    View Slide

  235. Forte inertie
    pour migrer

    View Slide

  236. Migrer vers
    RxJava 2 ou Reactor

    View Slide

  237. RxJava RxJava 2 Reactor
    Retrofit Oui Oui Non
    RxAndroid Oui Oui Non
    Realm Oui Non Non
    Hystrix Oui Non Non
    Couchbase Oui Non Non
    MongoDB Oui Non Non
    Spring Data 2.0 Oui Non Oui
    Reactor IPC Non Non Oui
    WebFlux Non Oui Oui
    Android Spring

    View Slide

  238. Spring 5 va accelerer
    l’adoption de Reactor

    View Slide

  239. View Slide

  240. View Slide

  241. Android
    RxJava 2

    View Slide

  242. Backend
    RxJava 2

    View Slide

  243. Spring
    Reactor

    View Slide

  244. 2017
    l’année des Reactive Streams

    View Slide

  245. Merci pour votre attention
    On reste en contact ?
    [email protected]
    @dwursteisen
    http://blog.soat.fr
    RefCard RxJava 2 bientôt disponible !

    View Slide