【Kotlin】華麗にNull回避

KotlinはNull安全なプログラム言語だといいますが、当然ながらNullを取りうる変数objに対して、`obj!!`なんてやっちゃったら、場合によっては落ちます。

ただKotlinにはJavaにはないスコープ関数や拡張関数、エルビス演算子などがあります。それらを活用すればあの忌々しいNullを華麗にかわすことができます。今回、比較的よく使うNull回避の実装をまとめておきます。

# 全てのオブジェクトがNullでない場合のみ処理を実行する１

あるオブジェクトがNullでない場合のみ、とある処理を実行したいケースはよくあると思います。普通は次のように書くと思います。

```kotlin
if (obj != null) {
    doSomething(obj)
}
```

この書き方自体問題があるわけではないのですが、次のようなケースの場合にちょっとした不都合があります。

1. `obj`がインスタンス変数の場合、スマートキャストが効かない
1. Nullチェックしたい変数が複数ある場合、if条件にタラタラと書かなきゃならない

1についてですが、マルチスレッド環境下の場合だと、他のスレッドからインスタンス変数の内容を書き換えられてしまう可能性があります。そのためKotlinはスマートキャストによって`obj`を非Nullとみなすことができません。

ですので、if内に書く処理内容が`obj`を非Nullを期待している場合、`obj`を使用する際は、保証できるなら`obj!!`と書くか、あらかじめローカル変数に移しておくとかしないといけません。

2については、大した問題ではないようにも思えますが、if条件を長々と書くのもアレですし、何よりNullチェックする全ての変数において 1 の問題がありますので、実は結構やっかいです。

というわけで、私は次のような拡張関数を定義して、上記のNull問題を回避しています。

```kotlin
inline fun <T> ensureNotNull(p1: T?, f: (p1: T) -> Unit) {
    if (p1 != null) f(p1)
}
```

これを使って先程のif文を修正すると、こんな感じになります。

```kotlin
ensureNotNull(obj) { o ->
    doSomething(o)
}
```

これなら`obj`に対してスマートキャストが効くので便利です。

これだけなら`?.let`や`?.also`でもいいのですが、関数名に「Nullじゃないよ」という訴求力！があるので、何がしたいのか自明です。また、複数の変数に対してNullチェックをかける場合にも展開が容易です。複数の場合だと、次のようになります。

```kotlin
inline fun <T1, T2> ensureNotNull(p1: T1?, p2: T2?, f: (p1: T1, p2: T2) -> Unit) {
    if (p1 != null && p2 != null) f(p1, p2)
}

inline fun <T1, T2, T3> ensureNotNull(p1: T1?, p2: T2?, p3: T3?, f: (p1: T1, p2: T2, p3: T3) -> Unit) {
    if (p1 != null && p2 != null && p3 != null) f(p1, p2, p3)
}
...
```

例えば２つの変数が非Nullであることを保証して処理を実行したい場合は、次のように書けます。

```kotlin
ensureNotNull(arg1, arg2) { a1, a2 ->
    doSomething(a1, a2)
}
```

実用的な例では、AndroidアプリのFragment内での利用なんかがあると思います。Fragmentから外部APIを非同期で実行し、受け取った結果をもって何らかの処理する場合です。非同期処理が終わった頃には`view`がNullになってたりする可能性があるので、そこは華麗に回避してあげなければなりません。

```kotlin
api.call(...) { result ->
    // 結果を受け取ったときには、すでにactivityやviewがNullかもしれない！
    ensureNotNull(activity, view) { a, v ->
       doSomething()
    }
}
```

またFragmentの親クラスやミックスインするInterface等で、次のようなメソッドを用意しておいてもいいかもしれません。

```kotlin
abstract class BaseFragment : Fragment() {
    protected inline fun ensureAlive(f: (activity: Activity, view: View) -> Unit) {
        if (!isDetached && activity != null && view != null) f(activity!!, view!!)
    }
}
```

いろいろ応用は効くと思います。

### 拡張関数の解読

ジェネリック関数に慣れてないと、Kotlinの拡張関数は意味不明に見えるかもしれないので、簡単に解説しておきます。

```kotlin
inline fun <T> ensureNotNull(p1: T?, f: (p1: T) -> Unit) {
    if (p1 != null) f(p1)
}
```

１行目の宣言部の説明です。

- 1行目: `<T>` ・・・ 今から`T`という型パラメータ使いますよー
- 1行目: `(p1: T?,` ・・・ １個目の引数はNull許容のT型で、名前は`p1`ですよー
- 1行目: `f: (p1: T) -> Unit)` ・・・ ２個目の引数は関数型の引数で、名前は`f`ですよー。`f`の関数定義なんですが、引数が非Nullの`T`型で`p1`という名前でして、戻り値はナシ（`Unit`）ですからねー

`inline`を付けているのは、簡単に言うとinline関数じゃないと関数`f`の中からreturnができなくなるからです。もっと知りたければ自分でググって見て下さい。

# 全てのオブジェクトがNullでない場合のみ処理を実行する２
*2019-05-25追記*

先程の`ensureNotNull`の代替案として、次のような関数を定義するのも手です。

```kotlin
fun <T1, T2> safe(t1: T1?, t2: T2?): Pair<T1, T2>? {
    return if (t1 == null || t2 == null) null else Pair(t1, t2)
}

fun <T1, T2, T3> safe(t1: T1?, t2: T2?, t3: T3): Triple<T1, T2, T3>? {
    return if (t1 == null || t2 == null || t3 == null) null else Triple(t1, t2, t3)
}
```

この`safe`関数を利用すれば、ｎullかもしれないオブジェクトのアンラップor即効リターンのコードが簡潔に書けます。

```kotlin
val (context, activity) = safe(context, activity) ?: return
val (context, activity, view) = safe(context, activity, view) ?: return
```

みたいな感じです。すごく便利。
なお変数１つの場合は普通に`val context = context ?: return`とやればいいです。

# エルビス演算子でフォールバック代入

なんか値が入ってたらそれを使うけど、Nullだったら既定値を使いたい、ってな場合です。

```kotlin
private fun assignName(name: String?) {
    val name = name ?: "[匿名さん]"

    doSomething(name)
}
```

なお、右辺の`name`は引数の`name`で左辺の`name`は新しく定義した変数扱いになります。別名を考えなくていいので便利です。Kotlin最高。

# エルビス演算子で速攻リターン

（さっきとほとんど同じ例なんですが）、Nullだったら早々にreturnしたい場合にもエルビス演算子が便利です。

```kotlin
fun makeAQuickReturn(str: String?) {
    str ?: return

    doSomething(str)
}
```

# エルビス演算子で例外発生

またまた同じような例ですが、AndroidのFragmentに必須パラメータが渡ってきてない場合なんかも。

```kotlin
val url = arguments?.getString(PARAM_URL) ?: throw Exception("URLは必須です")
```

# Nullかもしれない値の三項演算的なこと

nullじゃなかったら、その値を使って、そうじゃなかったらnullにままでいい、というようなケースです。kotlinの`if ~ else`は値を返すので三項演算子的に書けますが、`let`を使った方がスッキリします。

`instance?.method()`はinstanceがnullでなければmethodを実行し、nullであればnullを返すので以下のように書けます。

```kotlin
fun decorate(name: String?) {
    val decoratedName = name?.let { "★$it★" }
    ...
}
```

`userId`がNullじゃなかったら検索しにいこう、とか。

```kotlin
val user = userId?.let { User.find(it) }
```

# 空文字じゃなければ実行、を代入と同時に

Nullじゃなくて空文字の例なんですが、空文字チェックと変数への代入を同時に行いたい場合がしばしばあると思います。例えば、次のような例です。

```kotlin
val name = doc.selectFirst(".input-title").attr("name")
if (name.isNotBlank()) {
    doSomething(name)
    ...
}
```

一時変数に落とすのが少々煩わしいです。
拡張関数を定義しておけば楽になります。

```kotlin
inline fun <T: CharSequence> T.isNotBlank(f: (t: T) -> Unit) {
    if (isNotBlank()) f(this)
}
```

これを使うと、先程の例はこのようになります。

```kotlin
doc.selectFirst(".input-title").attr("name").isNotBlank { name ->
    doSomething(name)
    ...
}
```

１行しか変わりませんが、然るべきスコープ内でしか有効でない一時変数を楽に定義できるので、相当気持ちいいです。

# 空リストでなければ実行、を代入と同時に

さっきの空文字の例のリスト版です。

```kotlin
inline fun <T: List<*>> T.isNotEmpty(f: (T) -> Unit) {
    if (isNotEmpty()) f(this)
}
```

```kotlin
doc.select("div.list").isNotEmpty { list ->
    doSomething(list)
}
```

# おしまい

とりあえず思い付いたものを列挙してみました。何かまた思い付いたら追記していきたいと思います。