RxJava Applied

30
RxJava Applied: Concise Examples where It Shines Igor Lozynskyi JEEConf - May 20-21, 2016 Software Engineer at GlobalLogic

Transcript of RxJava Applied

Page 1: RxJava Applied

RxJava Applied: Concise Examples where It Shines

Igor Lozynskyi

JEEConf - May 20-21, 2016

Software Engineer at GlobalLogic

Page 2: RxJava Applied

Presentation’s home

https://github.com/aigor/rx-presentation

Page 3: RxJava Applied

Modern apps

Created with draw.io

Page 4: RxJava Applied

Options to deal with integration complexity

JDeferred

CompletableFuture<T>

Scala.Rx

Scala ActorsRxJava

Page 5: RxJava Applied

RxJavahttp://reactivex.iohttps://github.com/ReactiveX/RxJava

Page 6: RxJava Applied

Short history

● From 2009 for .NET● From 2013 for JVM (latest: 1.1.5, May 5, 2016)● Now a lot of other languages

Page 7: RxJava Applied

Use case: Stream of tweets

Created with Balsamiq Mockups

Page 8: RxJava Applied

Twitter API

Twitter Stream API (WebSocket alike):● Doc: https://dev.twitter.com/streaming/overview● Library: com.twitter:hbc-core:2.2.0

Twitter REST API:● GET https://api.twitter.com/1.1/users/show.json?screen_name=jeeconf● GET https://api.twitter.com/1.1/search/tweets.json?q=from:jeeconf

Page 9: RxJava Applied

Observer

interface Observer<T> {

void onNext(T t);

void onCompleted();

void onError(Throwable e);

}

Page 10: RxJava Applied

Observable .create(s -> { s.onNext("A"); s.onNext("B"); s.onCompleted(); }) .subscribe(m -> log.info("Message received: " + m), e -> log.warning("Error: " + e.getMessage()), () -> log.info("Done!"));

Output:Message received: AMessage received: BDone!

Page 11: RxJava Applied

Let’s look at entities

class Tweet { String text; int favorite_count; String author; int author_followers;}

class Profile { String screen_name; String name; String location; int statuses_count; int followers_count;}

class UserWithTweet { Profile profile; Tweet tweet;}

Page 12: RxJava Applied

Marble diagram

Page 13: RxJava Applied

Profile getUserProfile(String screenName) { ObjectMapper om = new ObjectMapper(); return (Profile) om.readValue(om.readTree( Unirest.get(API_BASE_URL + "users/show.json") .queryString("screen_name", screenName) .header("Authorization", bearerAuth(authToken.get())) .asString() .getBody()), Profile.class);}

Get user profile synchronously

Page 14: RxJava Applied

Get user profile asynchronously

Observable<Profile> getUserProfile(String screenName) { return Observable.fromCallable(() -> { ObjectMapper om = new ObjectMapper(); return (Profile) om.readValue(om.readTree( Unirest.get(API_BASE_URL + "users/show.json") .queryString("screen_name", screenName) .header("Authorization", bearerAuth(authToken.get())) .asString()

.getBody()), Profile.class); });}

Page 15: RxJava Applied

Add some errors handling

Observable<Profile> getUserProfile(String screenName) { if (authToken.isPresent()) { return Observable.fromCallable(() -> { ObjectMapper om = new ObjectMapper(); return (Profile) om.readValue(om.readTree( Unirest.get(API_BASE_URL + "users/show.json") .queryString("screen_name", screenName) .header("Authorization", bearerAuth(authToken.get())) .asString() .getBody()), Profile.class); }).doOnCompleted(() -> log("getUserProfile completed for: " + screenName)); } else { return Observable.error(new RuntimeException("Can not connect to twitter")); }}

Page 16: RxJava Applied

Let’s do something concurrently

Illustration: Arsenal Firearms S.r.l.

Page 17: RxJava Applied
Page 18: RxJava Applied

Get data concurrently

Observable<UserWithTweet> getUserAndPopularTweet(String author){ return Observable.just(author) .flatMap(u -> { Observable<Profile> profile = client.getUserProfile(u) .subscribeOn(Schedulers.io()); Observable<Tweet> tweet = client.getUserRecentTweets(u) .defaultIfEmpty(null) .reduce((t1, t2) -> t1.retweet_count > t2.retweet_count ? t1 : t2) .subscribeOn(Schedulers.io()); return Observable.zip(profile, tweet, UserWithTweet::new); });}

Page 19: RxJava Applied
Page 20: RxJava Applied

Let’s subscribe on stream of tweets!

Page 21: RxJava Applied

streamClient.getStream("RxJava", "JEEConf", "Java")

Page 22: RxJava Applied

streamClient.getStream("RxJava", "JEEConf", "Java", "Trump")

Page 23: RxJava Applied

streamClient.getStream("RxJava", "JEEConf", "Java", "Trump")

.distinctUntilChanged()

.map(p -> p.author)

.flatMap(name -> getUserAndPopularTweet(name))

.subscribeOn(Schedulers.io())

.observeOn(Schedulers.immediate())

.subscribe(p -> log.info("The most popular tweet of user " + p.profile.name + ": " + p.tweet));

.scan((u1, u2) -> u1.author_followers > u2.author_followers ? u1 : u2)

Page 24: RxJava Applied

streamClient.getStream("RxJava", "JEEConf", "Java", "Trump") .scan((u1, u2) -> u1.author_followers > u2.author_followers ? u1 : u2) .distinctUntilChanged() .map(p -> p.author) .flatMap(name -> { Observable<Profile> profile = client.getUserProfile(name) .subscribeOn(Schedulers.io()); Observable<Tweet> tweet = client.getUserRecentTweets(name) .defaultIfEmpty(null) .reduce((t1, t2) -> t1.retweet_count > t2.retweet_count ? t1 : t2) .subscribeOn(Schedulers.io()); return Observable.zip(profile, tweet, UserWithTweet::new); }) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.immediate()) .subscribe(p -> log.info("The most popular tweet of user " + p.profile.name + ": " + p.tweet));

Page 25: RxJava Applied

Marble diagram

Page 26: RxJava Applied

▸ API is big (150+ methods to remember)▸ Requires to understand underlying magic▸ Hard to debug▸ Don’t forget about back pressure

Conclusions: pitfalls

Page 27: RxJava Applied

▸ It is functional, it is reactive*

▸ Good for integration scenarios

▸ Allows to control execution threads

▸ Easy to compose workflows

▸ Easy to integrate into existing solutions

▸ Easy to test

* RxJava is inspired by FRP (Functional Reactive Programming), but doesn’t implement it

Conclusions: strength

Page 28: RxJava Applied
Page 29: RxJava Applied

Q&A

Page 30: RxJava Applied

Thanks

Presentation template by SlidesCarnival

@[email protected]