Java8のStream APIを使ってforループを無くすという記事。面白そうだったのでRxJava化しました。AndroidだとJava8 Stream API使えないですからね (´・ω・`)。Java8世界ではRxJavaってどういう位置づけなんでしょう気になります。
元記事と同じ様に、forループのあるコードとRxJavaでのコードを並べる形にします。Articleクラスについてはコチラには記載しないので元記事を見て下さい。シンプルなモデルなので見るまでもないかもしれません。
AndroidでのJava8環境構築は、
RxAndroidとRetrolambdaで大体Java8をAndroidに持ち込む - visible true を参照して下さい。
getFirstJavaArticle()
タグにJava
を含む最初のArticleを返す。
for loop
public Article getFirstJavaArticle() { for (Article article : articles) { if (article.getTags().contains("Java")) { return article; } } return null; }
RxJava
AndroidなJava8ではOptionalがないのでObservable
public Observable<Article> getFirstJavaArticle() { return Observable.from(articles) .filter(articles -> articles.getTags().contains("Java")) .firstOrDefault(null); }
使い方
即座に値を取り出すなら以下。
Article first = getFirstJavaArticle().toBlocking().single(); if (first != null) { //do something... }
subscribeできるなら、
getFirstJavaArticle() .filter(articles -> articles != null) .subscribe(articles -> { //do something... });
getAllJavaArticles()
タグにJava
を含む全てのArticleを返す。
for loop
public List<Article> getAllJavaArticles() { List<Article> result = new ArrayList<>(); for (Article article : articles) { if (article.getTags().contains("Java")) { result.add(article); } } return result; }
RxJava
Stream APIと比べると呼び出しが多い。
public List<Article> getAllJavaArticles() { return Observable.from(articles) .filter(articles -> articles.getTags().contains("Java")) .toList() .toBlocking() .single(); }
groupByAuthor()
author
をkey、Article一覧をvalueとしたMapを返す。
for loop
public Map<String, List<Article>> groupByAuthor() { Map<String, List<Article>> result = new HashMap<>(); for (Article article : articles) { if (result.containsKey(article.getAuthor())) { result.get(article.getAuthor()).add(article); } else { ArrayList<Article> articles = new ArrayList<>(); articles.add(article); result.put(article.getAuthor(), articles); } } return result; }
RxJava
RxJavaではCollectorsに代わるものはなさそうでちょっと汚い感じに。もっといい方法があるかも。toBlocking()
をcollect()
の中で呼んでるとsubscribedOn(), observeOn()のスレッド関係なくデッドロックする問題にはまりました。
public Map<String, List<Article>> groupByAuthor() { return Observable.from(articles) .groupBy(Article::getAuthor) .collect(new HashMap<String, List<Article>>(), (m, o) -> { o.toList().subscribe(list -> m.put(o.getKey(), list)); }) .toBlocking().single(); }
getDistinctTags()
タグのセットを返す。
for loop
public Set<String> getDistinctTags() { Set<String> result = new HashSet<>(); for (Article article : articles) { result.addAll(article.getTags()); } return result; }
RxJava
こちらもちょっと冗長。HashSet<String>::new
って渡せなかったのが悔やまれる。
public Set<String> getDistinctTags() { return Observable.from(articles) .flatMap(article -> Observable.from(article.getTags())) .distinct(tag -> tag) .toList() .map(list -> new HashSet<>(list)) .toBlocking().single(); }
まとめ
- Java8はサイコーである
- RxJavaでも頑張ればStream API的な事が出来そう
- No more loops
- forループだけでなくifもなくなっている事がわかる
- 各処理が分割されているのでやりたいことが明快になる
- RxJava世界から値を取り出すのはちょっと冗長