Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

RxJava Applied

418 views

Published on

RxJava Applied: Concise Examples where It Shines
JEEConf - May 20-21, 2016
by Igor Lozynskyi

Published in: Software
  • Be the first to comment

  • Be the first to like this

RxJava Applied

  1. 1. RxJava Applied: Concise Examples where It Shines Igor Lozynskyi JEEConf - May 20-21, 2016 Software Engineer at GlobalLogic
  2. 2. Presentation’s home https://github.com/aigor/rx-presentation
  3. 3. Modern apps Created with draw.io
  4. 4. Options to deal with integration complexity JDeferred CompletableFuture<T> Scala.Rx Scala Actors RxJava
  5. 5. RxJava http://reactivex.io https://github.com/ReactiveX/RxJava
  6. 6. Short history ● From 2009 for .NET ● From 2013 for JVM (latest: 1.1.5, May 5, 2016) ● Now a lot of other languages
  7. 7. Use case: Stream of tweets Created with Balsamiq Mockups
  8. 8. 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
  9. 9. Observer interface Observer<T> { void onNext(T t); void onCompleted(); void onError(Throwable e); }
  10. 10. 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: A Message received: B Done!
  11. 11. 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; }
  12. 12. Marble diagram
  13. 13. 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
  14. 14. 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); }); }
  15. 15. 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")); } }
  16. 16. Let’s do something concurrently Illustration: Arsenal Firearms S.r.l.
  17. 17. 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); }); }
  18. 18. Let’s subscribe on stream of tweets!
  19. 19. streamClient.getStream("RxJava", "JEEConf", "Java")
  20. 20. streamClient.getStream("RxJava", "JEEConf", "Java", "Trump")
  21. 21. 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)
  22. 22. 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));
  23. 23. Marble diagram
  24. 24. ▸ API is big (150+ methods to remember) ▸ Requires to understand underlying magic ▸ Hard to debug ▸ Don’t forget about back pressure Conclusions: pitfalls
  25. 25. ▸ 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
  26. 26. Q&A
  27. 27. Thanks Presentation template by SlidesCarnival @siromaha aigooor@gmail.com

×