Kotlin1.4で使いたい新機能を一部紹介する

# 背景
8/17に`Kotlin 1.4`がリリースされました。
Androidエンジニアの自分から見てこれは使いたいと思えるものが多かったので、使いたいものを抜粋・紹介したいと思います。

# 新機能

## SAM変換のKotlin対応

これまでSAM(=Single Abstract Method)変換はJavaのコードにのみ対応しているという状況でした。
例えばクリックイベントでよく使う`View.OnClickListener`はjavaで書かれているためラムダ式の省略など様々な形でかけていたわけですね。

```View.java
/**
 * Interface definition for a callback to be invoked when a view is clicked.
 */
public interface OnClickListener {
    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    void onClick(View v);
}
```

それが`.kt`のものに対してもSAM変換ができるようになりました。

## 名前付き引数とポジショナル引数の混在が可能に
データクラスやメソッドにて[名前付き引数](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/functions.html#%E5%90%8D%E5%89%8D%E4%BB%98%E3%81%8D%E5%BC%95%E6%95%B0)が以前からサポートされていて、使っている方もいらっしゃるのではないでしょうか。
それを使う際に、引数が複数ある状態で名前付き引数とそのままを混在することはこれまでできませんでした。

例えば、

```Book.kt
data class Book(val title: String, val author: String, val translator: String, val price: Int)
```

というデータクラスを定義した場合、これを宣言する際に

```Snippet.kt
val book = Book(
    title = "Sample Title",
    "Sample Author", // author=としないとダメ
    (略)
)
```

というように混在して宣言することができなかったわけですね。これが1.4から混在して宣言することが可能になりました。
そのため、わかりづらかったり混同しやすい引数に関しては名前付き引数を適用、そうでないものはそのまま値を入れるなど皆がとても理解しやすい形でコーディングできそうです。

## 末尾カンマ
JavaScriptはじめ他言語ではよく見かける末尾カンマがサポートされるようになりました。上述したデータクラスを例にとると、

```Book.kt
data class Book(val title: String, val author: String, val translator: String, val price: Int,)
```

このように最後にカンマを宣言してもコンパイルエラーにならなくなりました。環境によってはLintで指摘をもらう可能性もありますがコーディング中はとても便利そうです。

## デフォルト引数を持つ関数に対しての関数呼び出し(::)が可能に

```Snippeet.kt
fun main() {
    println(apply(::toLength))
}

fun toLength(s: String? = null) = if (s == null) {
    0
} else {
    s.length
}

fun apply(func: () -> Int): Int = func()
```

`apply(::toLength)`の部分を見てもらうと、引数宣言をしないと動かないのでは？と思いますが、デフォルト引数を参照してくれるようになりました

このコードの場合、`toLength`デフォルトが`null`のため`0`が返りそれがprintされていることになります。

これまでは`apply(::toLength)`とするには、`apply`部分をそのまま使うことはできず、

```
fun apply(func: (String?) -> Int): Int = func(null)
```
このような形で関数に対してデフォルト値を宣言する必要がありました。

## Unitを返す関数に対して任意の型を返す関数呼び出し(::)が可能に

同様にUnitを返す関数に対しても関数呼び出しができるようになりました。

```Snippet.kt
fun main() {
    foo { hoge() } // 1.4以前での書き方
    foo(::hoge) // 1.4からの書き方
}

fun foo(f: () -> Unit) {}

fun hoge() = "hoge"
```

# IDE上の新しいツール

## Coroutine Debugger

RxからCoroutineに乗り換えた、Coroutineを使っているという人は多いのではないでしょうか。
ただし、デバッグするうえではやりづらいことも多くありました。コルーチンはスレッド間を行き来するので、特定のコルーチンでの処理が知りたかったり、そのコンテキストをチェックすることが困難でした。
場合によっては、ブレークポイント上のステップの追跡が機能しなかったりしていました。
そこで、IDEの`Debug Tool Window`上に`Coroutine`のタブができました。

<img width="1200" src="https://kotlinlang.org/assets/images/reference/whats-new/coroutine-debugger-wn.png"/>

これによって以下のことが可能になりました。

* 各コルーチンの状態を簡単に確認できる
* 実行中と一時停止中の両方のコルーチンのローカル変数とキャプチャされた変数の値を確認できる
* コルーチンのスタックを見ることができる

Coroutineを導入している場合は、デバッグするうえでとても助かる機能ですね。

<font color="red">※ kotlinx-coroutines-coreのバージョンが1.3.8以上である必要があります </font>

# コンパイラ

速度改善はじめ後述する型推論まわりも強化されました。

## ラムダ式のスマートキャスト

```Snippet.kt
val result = run {
    var str = getNullableTitle() // String?が返る
    if (str == null) {
        str = "Sample Title"
    }
    str
}
```

このコードを例にとると、返る値は明らかに`non-null`であるとわかるのですが、スマートキャストはこれまでされず`String?`が返ってきていました。
1.4からはこの値が`String`として返ってくるようになります。

## デリゲートプロパティの型推論の改善

```Snippet.kt
import kotlin.properties.Delegates

fun main() {
    var prop: String? by Delegates.observable(null) { p, old, new ->
        println("$old → $new")
    }
    prop = "abc"
    prop = "xyz"
}
```

以前ではこのような書き方だとコンパイルエラーになっていましたが、1.4からこの`old`, `new`に対して`String?`と認識してくれるようになりました。

# 標準ライブラリ

## collectionsに対する機能追加

### setOfNotNull()

non-nullなもののみ返してくれます

```Snippet.kt
val set = setOfNotNull(null, 1, 2, 0, null)
println(set) // [1, 2, 0]
```

### shuffled() がsequencesに対して適応可能に

```Snippet.kt
val numbers = (0 until 50).asSequence()
val result = numbers.map { it * 2 }.shuffled().take(5)
```

### IndexedがonEach()/flatMap()に追加

```Snippet.kt
listOf("a", "b", "c", "d").onEachIndexed {
    index, item -> println(index.toString() + ":" + item)
}

val list = listOf("hello", "kot", "lin", "world")
val kotlin = list.flatMapIndexed { index, item ->
    if (index in 1..2) item.toList() else emptyList() 
}
```

flatMapは自身よく使うのでさらに快適にかけそうです

### OrNullがrandom/reduce/reduceIndexedに追加

例えばemptyListに対してrandom()をすると`Collection is empty`と例外が出されます

```Snippet.kt
val empty = emptyList<Int>()
println(empty.random())
```

それに対してOrNullが追加されたことでその場合にnullが返るようになりました。

```Snippet.kt
val empty = emptyList<Int>()
println(empty.randomOrNull()) //nullが返る
```

emptyListが返ることも多くあると思うのでとても便利になりましたね。reduceで結構使うのではないでしょうか。


### runningFold()/runningReduce()

これまで`fold/reduce`を使っていてその途中結果も含めた配列を取得したいと思うことがあったのではないでしょうか。わざわざその要素を`append`するのは面倒だったのですが、それがサポートされるようになりました。

```Snippet.kt
val numbers = mutableListOf(0, 1, 2, 3, 4, 5)
val runningReduceSum = numbers.runningReduce { sum, item -> sum + item } // [0, 1, 3, 6, 10, 15]
val runningFoldSum = numbers.runningFold(10) { sum, item -> sum + item } // [10, 10, 11, 13, 16, 20, 25]
```

### sumOf()/minOf()/maxOf()

条件に対する合計値/最小値/最大値を返すことができます

```Snippet.kt
val order = listOf<OrderItem>(
    OrderItem("Cake", price = 10.0, count = 1),
    OrderItem("Coffee", price = 2.5, count = 3),
    OrderItem("Tea", price = 1.5, count = 2))

val total = order.sumOf { it.price * it.count} // Double
val count = order.sumOf { it.count } // Int
```

# JSON serialization

1.4から[kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization)がstableとなりました。
`Gson`がdeprecatedになり、`Moshi`を使う方が多かったと思いますが、この機会に`serialization`を試してみてはどうでしょうか。

# おわりに

以上かいつまみつつ一部紹介しました。下の参考には他機能もたくさんあるのでチェックしてみてください。
1.4でかなり進化したKotlinを是非是非導入して快適なコーディングを！

間違い等あれば遠慮なく指摘いただければと思います

## 参考

https://kotlinlang.org/docs/reference/whatsnew14.html#whats-new-in-kotlin-140