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とOptionalで
関数型Androidしよう
shibuya.apk #2 2015-07-30
• 白山 文彦(しろやま ふみひこ)
• 株式会社マナボ 技術者
• @fushiroyama / fu.shiroyama@gmail.com
• ナマポではありません。これだけ覚えて帰ってく
ださい。
• すごいHaskellたのしく学ぼう...
お詫び
• 「関数型」とタイトルに入れましたが誤解を招
きやすいので資料の最後で発表者の考える関数
型プログラミングについて補足してあります。
Optional
• Haskell
• Maybe a = Nothing ¦ Just a
• Scala
• Option[T] = Some(T) ¦ None
• あるかもしれないし、ないかもしれない
• ないかもしれない可能性を型で明示
• ないかもしれないまま扱える
• Map#get…キーがなければnull
• String#indexOf…見つからなければ-1
• 特定条件下で返り値がない、いつもと違うケー
スではOptionalを使うチャンス!
Android doesn t
suport Java 8
• RxJavaのObservable<T>でOptional<T>を代行
する (by id:sys1yagi)
• http://sys1yagi.hatenablog.com/entry/
2015/01/26/183000
• 神いわゆ...
• eccyan/RxJava-Optional
• https://github.com/eccyan/RxJava-Optional
• 素晴らしすぎます。ありがとうございます。
repositories {
jcenter()
}
dependencies {
compile 'io.reactivex:rxandroid:0.25.0'
compile 'com.eccyan:rxjava-optional:1.1....
早速使おう!
Optional作る
• Optional.of(T)
• Optional.ofNullable(T)
• Optional.empty()
• Optional.of(null)
• NullPointerException
• Optional.ofNullable(null)
• OK!
• Optional.empty = Optional.ofNullable(null)
• その式でNonNullであることが自明である場合
はOptional.of()を使う
• Optional.ofNullable()を毎回使うみたいな考え
方は誤り!
Optional使う
• Optional#get()
• Optional#orElse(T)
• Optional#orElseCall(() -> {T})
• Optional#orElseThrow(() -> {Throwable})
• Optional#get
• 見つからなければNoSuchElementException
• Optional#orElse(elseValue)
• Optional#orElseCall(() -> elseValue)
• ラムダ式...
• Optional#get は中身があるかどうか意識する必
要があるのであまり使わない
• if (opt.isPresent) { opt.get() } とかは最悪
• orElseとorElseCallの違いは、後者はemptyの
場合...
Maybeモナド的に使う
• Optional#ifPresent(val -> {})
• Optional#map(T -> U)
• Optional#flatMap(T -> Optional<U>)
• Optional#filter(P...
Optional#ifPresent
Optional<String> opt = Optional.of(getOpt());
opt.ifPresent(s -> Log.i(TAG, s));
nullのときは何もしない
Optional#map
Optional<String> nameOpt =
entityOpt.map(userEntity -> userEntity.getFirstName());
entityOpt.map(UserEntity::...
Optional#flatMap
Optional<Optional<T>>を
flatten(平らにする)イメージ
Optional<AnotherOptional> anotherOpt =
entityOpt.flatMap(userEntit...
Optional#filter
a -> Bool -> a
String userName = entityOpt
.filter(entity -> entity.getUserName.contains( hoge ));
String userName = entityOpt
.filter(entity -> !TextUtils.isEmpty(entity.getUserName()))
.map(UserEntity::getUserName)
.orEl...
Optional総括
• ほぼ完全なOptionalがAndroidでも使える
• 幾つかメソッド名が違ったり、SupplierやFunctionなどの関数オブジェクト型がRxJavaの
Action1やFunction1で置き換えられているが...
RxJava
RxJava
• https://github.com/ReactiveX/RxJava
• オブザーバパターンを拡張してデータやイベントの
シーケンス(一連の流れ)をサポートし、これらの
シーケンスを宣言的に組み合わせるオペレータを提
供する...
インストール
• compile io.reactivex:rxandroid:0.25.0'
• RxAndroidを入れるとRxJavaも一緒に入る
• RxAndroidは現時点で大きくなりすぎて開発者の間でライ
ブラリの分割が検討されて...
• プロミスとしての使われ方が一番一般的
• 将来起こる一連のイベントの流れを表現する
• 非同期通信の結果
• ユーザのタッチイベント
• リスト
• 参考)RxJava学習のベストプラクティスっぽいもの by yagi
• https://...
Observable
• オブザーバパターンの観測対象に相当
• イベントドリブンに結果が通知されてくる
• 観測者(わたくしども)はObservableをsubscribe(購読)し、
結果を好きなようにし、不要なタイミングでunsubscr...
結果を受け取る
• onNext(result -> {})
• 例えばユーザタッチイベントのObservableはユーザがタッチするごとにonNextにコールバックされる
• 非同期通信のObservableはここで結果を受け取る
• onE...
Retrofitで試す
• compile com.squareup.retrofit:retrofit:1.9.0'
• @GET("/user/{id}/photo")

void getUserPhoto(@Path("id") int id,...
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.build();
GitHubService service...
で、何が嬉しいの?
Observableは連結できる!
各種オペレータは後述
こんなことが簡単に!
Observable<Token> tokenObservable = getTokenObservable();
tokenObservable
.flatMap(token -> getUserIn...
重要ポイントおさらい
• Observableはいくつでも連結できるよ(複数の
Observableの連結方法はこのあと出てくる)
• 複数のObservableがそれぞれ非同期処理をするとして、
それぞれをシーケンシャルに実行して結果を次々渡...
実行場所と観測場所
• Observable#subscribeOn
• Observableがsubscribeされるスレッドを指定(処理が実行されるスレッドと考えて差し支えない)
• Observableごとに異なるsubscribeOnを...
GitHubService service = restAdapter.create(GitHubService.class);
service.getUserPhoto(12345)
.subscribeOn(Schedulers.newTh...
各種オペレータ
• map
• Observable<T> -> U
• flatMap
• Observable<T> -> Observable<U>
• filter
• retry
• take
• などなど…便利なのが山ほどある
Observableを連結する
• Observable.merge
• Observable.concat
• Observable.zip
• Observable.combineLatest
Observable.merge
• 複数のObservableを1つにまとめる
• 各々のObservableから排出されるアイテムTは
排出された時系列に並べれる(パラレル)
Observable.concat
• 複数のObservableを1つにまとめる
• 各々のObservableから排出されるアイテムTは
前のObservableから排出された順、次の
Observableから排出された順というふうに並べ
...
Observable.zip
• 複数のObservableを1つにまとめる
• 各々のObservableから排出されるアイテムTは
ひとつめのObservableから排出された最新のも
のと、もうひとつのObservableから排出された
...
Observable.combineLatest
• 複数のObservableを1つにまとめる
• 複数のObservableの、それぞれ最後のアイテムにfuncを適用して新し
い結果を次に返す。
• funcは複数のObservableのど...
WidgetもObservableに
Observable.combineLatest(
WidgetObservable.text(editTextNickname),
WidgetObservable.text(editTextPhone)...
まとめ
• Observable(ストリーム)をリストと考えると、
リストに対して関数をmap(写像)して違う結果を
得るというのは非常に関数型プログラミング的でとっ
つきやすい
• Observableと前出のOptional(今回は実質同じ...
Androidで関数型プログラミング
• あるデータ構造(しばしばリスト)aに関数を適用して別のデー
タ構造bを得る。(a -> b) -> [a] -> [b]
• Maybe的にデータ構造の中身を取り出すことなく利用する
• こういったプロ...
いい忘れ
• ラムダ式はRetrolambdaで使えます
• ラムダ式
• メソッド参照
• ちょっとインストールややこしいので後で加筆
します。
ご静聴ありがとうございました。
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしよう
Upcoming SlideShare
Loading in …5
×

Rxjavaとoptionalで関数型androidしよう

3,952 views

Published on

Rxjavaとoptionalで関数型androidしよう @Shibuya.apk #2

Published in: Software
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Rxjavaとoptionalで関数型androidしよう

  1. 1. RxJavaとOptionalで 関数型Androidしよう shibuya.apk #2 2015-07-30
  2. 2. • 白山 文彦(しろやま ふみひこ) • 株式会社マナボ 技術者 • @fushiroyama / fu.shiroyama@gmail.com • ナマポではありません。これだけ覚えて帰ってく ださい。 • すごいHaskellたのしく学ぼう読書会やってま す!求む同士!気軽に話しかけて下さい!
  3. 3. お詫び • 「関数型」とタイトルに入れましたが誤解を招 きやすいので資料の最後で発表者の考える関数 型プログラミングについて補足してあります。
  4. 4. Optional
  5. 5. • Haskell • Maybe a = Nothing ¦ Just a • Scala • Option[T] = Some(T) ¦ None
  6. 6. • あるかもしれないし、ないかもしれない • ないかもしれない可能性を型で明示 • ないかもしれないまま扱える
  7. 7. • Map#get…キーがなければnull • String#indexOf…見つからなければ-1 • 特定条件下で返り値がない、いつもと違うケー スではOptionalを使うチャンス!
  8. 8. Android doesn t suport Java 8
  9. 9. • RxJavaのObservable<T>でOptional<T>を代行 する (by id:sys1yagi) • http://sys1yagi.hatenablog.com/entry/ 2015/01/26/183000 • 神いわゆるゴッド • RxJava(後述)でOptionalを代用
  10. 10. • eccyan/RxJava-Optional • https://github.com/eccyan/RxJava-Optional • 素晴らしすぎます。ありがとうございます。
  11. 11. repositories { jcenter() } dependencies { compile 'io.reactivex:rxandroid:0.25.0' compile 'com.eccyan:rxjava-optional:1.1.2' } バージョン注意
  12. 12. 早速使おう!
  13. 13. Optional作る • Optional.of(T) • Optional.ofNullable(T) • Optional.empty()
  14. 14. • Optional.of(null) • NullPointerException • Optional.ofNullable(null) • OK! • Optional.empty = Optional.ofNullable(null)
  15. 15. • その式でNonNullであることが自明である場合 はOptional.of()を使う • Optional.ofNullable()を毎回使うみたいな考え 方は誤り!
  16. 16. Optional使う • Optional#get() • Optional#orElse(T) • Optional#orElseCall(() -> {T}) • Optional#orElseThrow(() -> {Throwable})
  17. 17. • Optional#get • 見つからなければNoSuchElementException • Optional#orElse(elseValue) • Optional#orElseCall(() -> elseValue) • ラムダ式の結果がelseValueに • Optional#orElseThrow(() -> Throwable)
  18. 18. • Optional#get は中身があるかどうか意識する必 要があるのであまり使わない • if (opt.isPresent) { opt.get() } とかは最悪 • orElseとorElseCallの違いは、後者はemptyの 場合に初めてラムダ式の中身が評価される • orElseThrowの多用は禁物。これするぐらいな らなぜ普通にthrowしないのか考えよう。
  19. 19. Maybeモナド的に使う • Optional#ifPresent(val -> {}) • Optional#map(T -> U) • Optional#flatMap(T -> Optional<U>) • Optional#filter(Predicator<T, Boolean> -> T)
  20. 20. Optional#ifPresent Optional<String> opt = Optional.of(getOpt()); opt.ifPresent(s -> Log.i(TAG, s)); nullのときは何もしない
  21. 21. Optional#map Optional<String> nameOpt = entityOpt.map(userEntity -> userEntity.getFirstName()); entityOpt.map(UserEntity::getFirstName); と表記可(メソッド参照)
  22. 22. Optional#flatMap Optional<Optional<T>>を flatten(平らにする)イメージ Optional<AnotherOptional> anotherOpt = entityOpt.flatMap(userEntity -> { return userEntity.getAnotherOptional(); });
  23. 23. Optional#filter a -> Bool -> a String userName = entityOpt .filter(entity -> entity.getUserName.contains( hoge ));
  24. 24. String userName = entityOpt .filter(entity -> !TextUtils.isEmpty(entity.getUserName())) .map(UserEntity::getUserName) .orElse(getString(R.string.default_name)); filterやorElseとかと組み合わせると 更に強力に!
  25. 25. Optional総括 • ほぼ完全なOptionalがAndroidでも使える • 幾つかメソッド名が違ったり、SupplierやFunctionなどの関数オブジェクト型がRxJavaの Action1やFunction1で置き換えられているがラムダ式を使う限り何も意識する必要がない • 外出しの変数とnullチェックやforループみたいな手続き的 な処理をかなり減らせる • パターンマッチもタプルもないが充分強力 • 正しく使う限りデメリットが思いつかないので積極的にプ ロジェクトに取り入れるべきだと思う ラムダ式は後述
  26. 26. RxJava
  27. 27. RxJava • https://github.com/ReactiveX/RxJava • オブザーバパターンを拡張してデータやイベントの シーケンス(一連の流れ)をサポートし、これらの シーケンスを宣言的に組み合わせるオペレータを提 供する。 • RxAndroidという、Androidで使って便利なRxJava 拡張(というのが適切かわからないですが)も存在 する
  28. 28. インストール • compile io.reactivex:rxandroid:0.25.0' • RxAndroidを入れるとRxJavaも一緒に入る • RxAndroidは現時点で大きくなりすぎて開発者の間でライ ブラリの分割が検討されており、RxAndroid固有の機能を 利用する場合は注意を要する • https://github.com/ReactiveX/RxAndroid/issues/172 • https://github.com/JakeWharton/RxBinding
  29. 29. • プロミスとしての使われ方が一番一般的 • 将来起こる一連のイベントの流れを表現する • 非同期通信の結果 • ユーザのタッチイベント • リスト • 参考)RxJava学習のベストプラクティスっぽいもの by yagi • https://speakerdeck.com/sys1yagi/rxjavaxue-xi-falsehesutohurakuteisutuhoimofalse
  30. 30. Observable • オブザーバパターンの観測対象に相当 • イベントドリブンに結果が通知されてくる • 観測者(わたくしども)はObservableをsubscribe(購読)し、 結果を好きなようにし、不要なタイミングでunsubscribe(購読 解除)する • プロミスと違い、いつ終わるとも知れない無限ストリームも表現 できる(例:ユーザのタッチイベントはいつ来るとも知れず、ユー ザが飽きてスマホを放り投げるまで永久に続くかもしれない)
  31. 31. 結果を受け取る • onNext(result -> {}) • 例えばユーザタッチイベントのObservableはユーザがタッチするごとにonNextにコールバックされる • 非同期通信のObservableはここで結果を受け取る • onError(e) • エラーが発生するとここで受け取る • onComplete() • 有限ストリームは最後にここが呼ばれる
  32. 32. Retrofitで試す • compile com.squareup.retrofit:retrofit:1.9.0' • @GET("/user/{id}/photo")
 void getUserPhoto(@Path("id") int id, Callback<Photo> cb); • @GET("/user/{id}/photo")
 Observable<Photo> getUserPhoto(@Path("id") int id);
  33. 33. RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://api.github.com") .build(); GitHubService service = restAdapter.create(GitHubService.class); service.getUserPhoto(12345) .subscribe( photo -> { doSomething(photo); } error -> {}, () -> {} // complete ); 購読! 非同期処理はこの瞬間はじまる。
  34. 34. で、何が嬉しいの?
  35. 35. Observableは連結できる!
  36. 36. 各種オペレータは後述 こんなことが簡単に! Observable<Token> tokenObservable = getTokenObservable(); tokenObservable .flatMap(token -> getUserInfoObservable(token, args)) .subscribe( userInfo -> { doSomething(userInfo) }, error -> {}, );
  37. 37. 重要ポイントおさらい • Observableはいくつでも連結できるよ(複数の Observableの連結方法はこのあと出てくる) • 複数のObservableがそれぞれ非同期処理をするとして、 それぞれをシーケンシャルに実行して結果を次々渡す などもお手の物。(もちろんパラレルにも出来る) • Observable自体は将来実行される何かなので、そのオ ブジェクト自体ができた時点では何も起こってないこ とに注意。
  38. 38. 実行場所と観測場所 • Observable#subscribeOn • Observableがsubscribeされるスレッドを指定(処理が実行されるスレッドと考えて差し支えない) • Observableごとに異なるsubscribeOnを指定みたいなことは出来ない。いくつ指定しても最初に指 定したものが使わる。 • Observable#observeOn • Observableがイベントを通知する先のスレッドを変更 • Androidの場合だと非同期処理の結果をViewに描画するときはMainThreadである必要があるので、 subscribeの直前でobserveOnにRxAndroidのAndroidSchedulers.mainThread()を指定すると便 利
  39. 39. GitHubService service = restAdapter.create(GitHubService.class); service.getUserPhoto(12345) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( photo -> { doSomething(photo); } error -> {}, () -> {} // complete ); ワーカスレッドで実行 メインスレッドに結果を 通知してもらう
  40. 40. 各種オペレータ • map • Observable<T> -> U • flatMap • Observable<T> -> Observable<U> • filter • retry • take • などなど…便利なのが山ほどある
  41. 41. Observableを連結する • Observable.merge • Observable.concat • Observable.zip • Observable.combineLatest
  42. 42. Observable.merge • 複数のObservableを1つにまとめる • 各々のObservableから排出されるアイテムTは 排出された時系列に並べれる(パラレル)
  43. 43. Observable.concat • 複数のObservableを1つにまとめる • 各々のObservableから排出されるアイテムTは 前のObservableから排出された順、次の Observableから排出された順というふうに並べ れる(シリアル)
  44. 44. Observable.zip • 複数のObservableを1つにまとめる • 各々のObservableから排出されるアイテムTは ひとつめのObservableから排出された最新のも のと、もうひとつのObservableから排出された 最新のものをペアにして関数に渡される
  45. 45. Observable.combineLatest • 複数のObservableを1つにまとめる • 複数のObservableの、それぞれ最後のアイテムにfuncを適用して新し い結果を次に返す。 • funcは複数のObservableのどれかのonNextが来るたびに適用され る。 • zipと似ているが、複数のObservableのそれぞれ最新の値を待ち合わせ るわけではない。どれかがonNextに来るたびに呼ばれて、値が新しく なったもの以外はこれまでの最新の値がfuncの引数に渡る。このこと によって、3つぐらいの条件が全て満たされたら○○みたいなのが非常 に書きやすくなる。これめっちゃつかえるので絶対に覚える必要あり。
  46. 46. WidgetもObservableに Observable.combineLatest( WidgetObservable.text(editTextNickname), WidgetObservable.text(editTextPhone), (onTextChangeEvent, onTextChangeEvent2) -> { return TextUtils.isEmpty(onTextChangeEvent.text()) && TextUtils.isEmpty(onTextChangeEvent2.text()); }) .subscribe( submitButton::setEnabled);
  47. 47. まとめ • Observable(ストリーム)をリストと考えると、 リストに対して関数をmap(写像)して違う結果を 得るというのは非常に関数型プログラミング的でとっ つきやすい • Observableと前出のOptional(今回は実質同じも の)を組み合わせると非常に表現の幅が広がる • すべてがObservableな世界ではObservableを組み 合わせるだけでアプリが完成する!
  48. 48. Androidで関数型プログラミング • あるデータ構造(しばしばリスト)aに関数を適用して別のデー タ構造bを得る。(a -> b) -> [a] -> [b] • Maybe的にデータ構造の中身を取り出すことなく利用する • こういったプログラミングスタイルが可能になることから 「Androidで関数型プログラミング」という表現を使いました • Androidで利用可能なJavaで参照透過性を強制するのは不可能 だし無意味だし高階関数も中途半端なので世間的には関数型プロ グラミングとは見なされないかもしれませんが、どうか広い心で 発表を楽しんでいただけたら幸いです
  49. 49. いい忘れ • ラムダ式はRetrolambdaで使えます • ラムダ式 • メソッド参照 • ちょっとインストールややこしいので後で加筆 します。
  50. 50. ご静聴ありがとうございました。

×