import me

"あなたの当たり前が誰かのためになる"

RxKotlin:{map, flatMap, filter, skip, take}編

はじめに

RxJavaを理解するという目的で書いてみました。

JavaじゃなくてKotlinでやっているのですが自分の理解を自分なりに書きとどめておこうと思います。

 

RxJavaとは

Javaでリアクティブプログラミングを行うためのライブラリです。

データを通知する生産者(Flowable / Observable)を生成し、その生産者が通知したデータを消費者(Subscriber / Observer)が受け取りそのデータを使って処理を行う構成がRxJavaの基本になります。

引用先:

RxJavaリアクティブプログラミング 著:須田智之

 

詳しい例が上の書籍に載っているのでまだ読んでいない方は購入してみてください。

とても分かりやすいです。

 

リアクティブプログラミングとは

リアクティブプログラミングとは、データが流れるように来ること(ストリーム)に着目し、データを受け取るたびに関連したプログラムが反応(リアクション)して処理を行うようにするプログラミングの考え方です。

参照:

codezine.jp

 

 

文字でみてもよくわからなかったので、とりあえずサンプルプログラムをKotlinで簡単に作って実際に手を動かして各オペレータを学んだのでまとめて残しておこうと思います。

 

オペレータとは

RxJavaでは生産者(Flowable / Observable)が通知したデータが消費者(Subscriber / Observer)に届くまでに必要なデータを破棄したり、データを変換したりして操作することです

一部引用:RxJavaリアクティブプログラミング 著:須田智之

データが流れてくるストリームの中でデータに対して変換処理を行うというようなイメージなのかなと思ってます。

 

取り合えず下記環境で試してみました。

  • 言語:Kotlin
  • IDE:InteliJ IDEA

雑すぎる気がするがまあいいとしよう。。

 

map

mapはデータを変換して通知するオペレータです。

取り合えずサンプルプログラムを作成して実行してみました。

サンプルプログラムはこちらです。

 

fun main(args: Array<String>) {
val array: Array<String> = arrayOf("allow", "bow", "", "dead")
Observable.from(array)
.map { it.length }
.subscribe({
println(it)
}, {})
}

 

文字のデータが流れてきたのに対してその長さにデータを変換して出力しています。

実行結果はこちらです。

 

f:id:rozkey59:20180210124403p:plain

 

 それぞれの文字の長さが出力されていることが分かります。

flatMap

flatMapメソッドはmapに似ているのですが、違うのは1つのデータから複数のデータを通知できる点があります。

 

サンプルプログラムを見ていきましょう。

fun main(args: Array<String>) {
val array: Array<String> = arrayOf("allow", "bow", "", "dead")
Observable.from(array)
.flatMap { i -> if (i == "bow") Observable.just("fuck") else Observable.just(i.length)}
.subscribe({
println(it)
}, {})
}

 

これは文字列を受け取って「bow」という単語だったらfuckという文字列に変換しそれ以外ならその文字列の長さを返すようにしています。

 

実行結果は以下になります。

f:id:rozkey59:20180210161717p:plain

確かに受け取ったデータから複数の(Flowable / Observable)を返して一つのデータから複数のデータを通知することができています。

 

filter

filterメソッドは通知するデータを制限できます。フィルターという名前から想像しやすい気がします。

以下、サンプルプログラムです。

fun main(args: Array<String>) {
val array: Array<String> = arrayOf("allow", "bow", "", "dead")
Observable.from(array)
.filter { !it.isEmpty() }
.subscribe({
println(it)
}, {})
}

今回はfilterで空文字の時はデータを通知しないようにしています。

実行結果は以下になります。

f:id:rozkey59:20180210162411p:plain

確かに三番目のデータが通知されていないことが分かります。

 

skip

skipメソッドは最初に通知されるデータを指定した範囲だけ除くことができ、後のデータを通知することができます。

以下、サンプルプログラムになります。

fun main(args: Array<String>) {
val array: Array<String> = arrayOf("allow", "bow", "community", "dead")
Observable.from(array)
.skip(2)
.subscribe({
println(it)
}, {})
}

受け取ったデータの最初の二つはデータを通知せず、後のデータを通知するようにしています。

 

実行結果は以下になります。

f:id:rozkey59:20180210162933p:plain

 

実行結果から確かに最初の二つのデータが取り除かれて、後のデータを通知することができています。今回はカウントして行っていますが指定した時間などでも範囲を指定することができます。

 

take

takeメソッドはskipと対照的に指定したデータ数や経過時間でデータを通知することができます。

以下、サンプルプログラムです。

fun main(args: Array<String>) {
val array: Array<String> = arrayOf("allow", "bow", "", "dead")
Observable.from(array)
.take(2)
.subscribe({
println(it)
}, {})
}

サンプルでは、最初の二つのデータだけを通知するようにしています。

 

実行結果が以下になります。

f:id:rozkey59:20180210163601p:plain

確かに最初の二件だけが表示されていることが確認できます。

 

まとめ

今回はRxJavaの5つのオペレータ{map, flatMap, filter, skip, take}の紹介でした。

間違っていたりしたらコメント頂けると嬉しいです。

オペレータの紹介などでは他の人もやっていらっしゃるので、実際にアプリ開発でのUseCaseやアンチパターンをまとめられたらいいのかなとか思いますが僕もまだ勉強中の身なので知識の整理と共に少しづつやっていこうかと思います。