炊きたてのご飯が食べたい

定時に帰れるっていいね。自宅勤務できるっていいね。子どもと炊きたてのご飯が食べられる。アクトインディでは積極的にエンジニアを募集中です。

Kotlin で Realm を操作する時に気をつけていること


アクトインディ Advent Calendar 2016 4日目の記事になります。「若者の結婚願望 子供時代、体験多いと強く 」といった記事が日本経済新聞に書かれていました。

www.nikkei.com

子ども時代に家族で沢山思い出を作っていると、将来、結婚して家庭を持ちたいという気持ちが強くなるといった結果が出たそうです。アクトインディでは、子どもとのお出かけ先を提案するサービスを運営していますが、家族の思い出作りに少しでもお役に立てるサービスにもっと良くしていこうと思える嬉しい記事でした。子どもとのお出かけ先に困っている方は、是非いこーよアプリを使ってみてください ^^

iko-yo.net

4日目の記事では kotlin で Realm を操作する時に気をつけていることについて書きたいと思います。kotlin は null安全の言語ですが、Realm は java で書かれている為、 Realm から要素を取得する際 kotlin の型推論を使って以下のように書くと、要素がない場合に NullPointerExceptionが発生します。

open class User(
    @PrimaryKey open var id: Int = 0,
    open var name: String = ""
)
val realm = Realm.getDefaultInstance()
val user = realm.where(User::class.java).findFirst()
Log.d("*****", user.id.toString()) // user は null の為 NullPointerException
realm.close()

realm の findFirst() メソッドの定義が public E findFirst() { ... } となっているので、 val user の部分は型推論が行われ、実際には val user: User = realm.where(User::class.java).findFirst() と宣言していることになります。

kotlin でも安全に使う為には、型推論を行わず以下のように書くことで null が返却されることを明示することができますが

val realm = Realm.getDefaultInstance()
val user: User? = realm.where(User::class.java).findFirst()
Log.d("*****", user?.id.toString()) // null と Log に表示される
realm.close()

val user: User と書くことができてしまう為、少しでも安全に Realm を操作できるように Realm の Extension を定義して、極力 Extension で定義したメソッドを利用するようにしています。

RealmExtension.kt

// nullable な要素を返却するようにメソッドを定義する
fun <T : RealmObject> Realm.findFirst(type: Class<T>): T? {
    return this.where(type).findFirst()
}

fun <T : RealmObject> Realm.findId(type: Class<T>, id: Int): T? {
    return this.where(type).equalTo("id", id).findFirst()
}

Extension で定義したメソッドを利用するには以下のように書きます

val realm = Realm.getDefaultInstance()
val user = realm.findFirst(User::class.java)
Log.d("*****", user?.id.toString()) // null と Log に表示される
realm.close()

PrimaryKey に良く指定する id で要素を検索することが多いので findId といったメソッドも定義しています。Realm には要素を全て取得する findAll メソッドがありますが、こちらは要素が1件もなかった場合は空の配列で返却されるので、特にメソッドを定義する必要はないかと思います。