はじめよう、Kotlin（上級編）


[導入編](http://qiita.com/SYABU555/items/25b1e81a2437d6a2559f)
[基本編](http://qiita.com/SYABU555/items/7cc5909c119ec9ab0288)
上級編　★イマココ

# はじめに

Kotlin基本編で触れたものでも
「お、やるじゃん」と思った方もいらっしゃると思いますが
ここではKotlinの真髄に触れていきます

プログラマー初心者の方は「？」となるかもしれませんが
中規模以上のプロジェクトになれば便利になるコーディング方法かと思います

# Scope Functions

スコープ関数はインスタンスに続けてラムダと一緒に使うことで、
そのインスタンスに対する処理をラムダにまとめて記載することができます
一覧に載せておきます

|スコープ関数 |レシーバの表現(※1) |戻り値 |
|:--:|:--:|:--:|
|let |it (T) |Any (R) |
|run |this (T) |Any (R) |
|also |it (T) |receiver (T) |
|apply |this (T) |receiver (T) |
|with |this (T) |Any (R) |
|takeIf (※2) |this (T) |Boolean |
|takeUnless (※2) |this (T) |Boolean |

※1: レシーバとは、スコープ関数をコールするときに使うインスタンスを指します
※2: 最後の２つは特殊なケースで、異常ケースを書くときに役立つ

これ、かなり使えます
この味をしめると、Javaに戻れません、まじで
なにより **レビューやデバッグが早くなり非常に助かります**

個人的に思う利点は以下４点

* インスタンスへの操作をラムダ内にまとめることができる
* 影響範囲をラムダ内におさめることができる
* 無駄なインスタンス生成をなくせる
* これらにより、長いコードが読みやすくなる

例えばこれが

```Kotlin
val data = Data()
data.initialize()
data.firstName = "Hiroki"
data.lastName = "Honda"
data.age = "29"
data.language = "Japanese"

dao.insert(data)
```

こうなります

```Kotlin
dao.insert(Data().apply {
    initialize()
    firstName = "Hiroki"
    lastName = "Honda"
    age = "29"
    language = "Japanese"
})
```


## let

Nullableな変数の後ろにつける形をよく見ます

* **ラムダ内では`it`でレシーバを表現する**
* **ラムダ内の戻り値は何でもいいです**

```Kotlin
val upperCase: String? = foo?.let { it.toUpperCase() }
```

これでいうと、Unitが返っています（戻り値なし）
仮に戻り値を指定したい場合は明示的に最終行に指定するか、
あるいは戻り値のもつfunctionをコールします

## run

* **ラムダ内では`this`でレシーバを表現する（省略可）**
* **ラムダ内の戻り値は何でもいいです**

```Kotlin
val frame: JFrame? = frameOrNull()
frame?.run {
    size = Dimension(600, 400)
    defaultCloseOperation = JFrame.EXIT_ON_CLOSE
    setVisible(true)
}
```

これでいうと、Unitが返っています（戻り値なし）
仮に戻り値を指定したい場合は明示的に最終行に指定するか、
あるいは戻り値のもつfunctionをコールします

## also

* **ラムダ内では`it`でレシーバを表現する**
* **ラムダ内の戻り値はレシーバ**

```Kotlin
val button = Button(this).also {
    it.text = "Click me"
    it.setOnClickListener { 
        startActivity(Intent(this, NextActivity::class.java))
    }
}
```

これでいうと、buttonが勝手に返ります

## apply

* **ラムダ内では`this`でレシーバを表現する（省略可）**
* **ラムダ内の戻り値はレシーバ**

```Kotlin
val button = Button(this).apply {
    text = "Click me"
    setOnClickListener { 
        startActivity(Intent(this, NextActivity::class.java))
    }
}
```

これでいうと、buttonが勝手に返ります

## with

* **ラムダ内では`this`でレシーバを表現する（省略可）**
* **ラムダ内の戻り値は何でもいいです**

あまり利用用途が思い浮かばない子
applyの劣化版といったイメージです

applyと異なり、戻り値に指定がありません
利用シーンは難しいですが、あるインスタンスに対しての処理をまとめたいときは便利かも

**でも、使ったことない**

```Kotlin
val frame: JFrame = with(JFrame("My App")) {
    size = Dimension(600, 400)
    defaultCloseOperation = JFrame.EXIT_ON_CLOSE
    setVisible(true)
    this
}
```

## takeIf

* **ラムダ内では`this`でレシーバを表現する（省略可）**
* **ラムダ内の戻り値はBoolean**
* **戻り値がfalseでnullを返す**

エルビス演算子と組み合わせて使うと、
異常ケースをまとめて書けるので便利です

```Kotlin
val params = request.takeIf{ isValidParameter(it) }.params ?: throw RuntimeException()
```

追記：nullチェックと一緒のとき、超便利にかけました

```Kotlin
val text = ""

text?.let {
    if (it.isNotEmpty() {
        // ...
    }
}
```

これがこう書ける

```Kotlin
val text = ""

text?.takeIf { it.isNotEmpty() }?.let {
    // ...
}
```

## takeUnless

* **ラムダ内では`this`でレシーバを表現する（省略可）**
* **ラムダ内の戻り値はBoolean**
* **戻り値がtrueでnullを返す**

takeIfの逆パターン

## TIPS

`it`には名前をつけることができます
可読性悪いなぁというときに使ってみましょう

```Kotlin
val button = Button(this).also {
    it.text = "Click me"
    it.setOnClickListener { 
        startActivity(Intent(this, NextActivity::class.java))
    }
}

// or

val button = Button(this).also { button ->
    button.text = "Click me"
    button.setOnClickListener { 
        startActivity(Intent(this, NextActivity::class.java))
    }
}

// or

val button = Button(this).also { button: Button ->
    button.text = "Click me"
    button.setOnClickListener { 
        startActivity(Intent(this, NextActivity::class.java))
    }
}
```

# Extension Function
Kotlinではクラスに外部拡張functionの追加が可能です

```Kotlin
class C

data class D(val param: Int): C()

fun C.foo() = "extended C.foo()"

fun D.foo() = "extended D.foo(), param=$param"
```

```result
extended C.foo()
extended D.foo(), param=4
```

もちろん既存クラスである`Int`などにも拡張可能です

## Example 1

利用シーンとしては、例えばDateクラスに対して火曜日かどうか判定するUtilityクラスを作ったとします
これがひとつだけであれば問題ありませんが、肥大化するにつれてやはり見づらくなる欠点があります

```Java
static boolean isTuesday(Date date) {
    return date.getDay() == 2;
}
```

呼び出す側としても、Utilityクラスを書くことで少しコードも長くなります

```Java
boolean tuesday = DateUtils.isTuesday(date);
```

また、このケースの場合は完全に引数のDateに依存するメソッドですので
できることならDateクラスに実装したいのに、と思うと思います

そんなときにExtensionを使いましょう

```Kotlin
fun Date.isTuesday(): Boolean = getDay() == 2
```

するとこのように、Dateインスタンスに対するコールのため、非常に読みやすくなります

```Kotlin
val tuesday = date.isTuesday()
```

## Example 2

例えばCursorから特定のColumnを特定し、値を取得したい場合、
Javaだとこのように長々と書く必要があります

```Java
String firstName = cursor.getString(
        cursor.getColumnIndexOrThrow("first_name"));
println(firstName != null ? firstName : "Unknown");
```

しかしKotlinのExtensionを使えばこのように完結に書くための
UtilityメソッドをCursorクラスに拡張して作成することが可能です

```Kotlin
fun Cursor.getStringOrNull(columnName: String): String? {
    val index = getColumnIndexOrThrow(columnName)
    return if (isNull(index)) null else getString(index)
}

fun Cursor.getString(columnName: String): String =
    getStringOrNull(columnName)!!
```

```Kotlin
val firstName = cursor.getStringOrNull("first_name")
println(firstName ?: "Unknown");
```

# High-Order Functions

高階関数というのが使えます
「は？」と思った方、ご安心ください、私も初めはそう思いました

```Kotlin
([引数]) -> [戻り値] 
```

こう書くと、 **functionなんかを擬似的に渡すことが可能になります**

とっつきにくいと思うので、
例として、高階関数を引数にとるExtensionを紹介します

## Example 1

```Kotlin
fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
    // ...
}
```

この書き方を解説すると

`<T> List<T>` ... 冒頭の`<T>`はジェネリック使いますよ！その中身はTですよ！の定義
`List<T>.filter(...): List<T>` ... List<>.filter 拡張関数を作る、戻り値はもちろん`List<>`
`(predicate: (T) -> Boolean)` ... `(T)`はひとつの処理、ラムダ`{}` を指し、その引数が`T`であることを指します。そして、その戻り値を`->`で指定します。
つまりこの場合は **「引数が T で戻り値がBooleanのラムダ{}」を引数としてとります**
ここを高階関数というそうです

中身をつめると

```Kotlin
fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
    val newList = ArrayList<T>()
    for (item in this) {
        if (predicate(item)) {
            newList.add(item)
            // ...
        }
    }
    return newList
}
```

利用する場合はこんな感じ

```Kotlin
val names = listOf("Jake", "Jesse", "Matt", "Alec")
val jakes = names.filter { it == "Jake" }
```

filter内の`it`は、namesリストの中身、つまりこのケースだとString型の変数を指します

## Example 2

例えばある特定のオブジェクトに対して同期処理を行いたい場合、
Javaでは`synchronized`を使っていたと思います

それがメンテナンスしやすい形でこのようにかけます

```Kotlin
data class Lock<T>(private val obj: T) {
    public fun acquire(func: (T) -> Unit) {
        synchronized (obj) {
            func(obj)
        }
    }
}
```

```Kotlin
val readerLock = Lock(JsonReader(stream))

// Later
readerLock.acquire {
    println(it.readString())
}
```

メソッドコールの段階で処理を書けばよくなるので、
いちいち`synchronized`を書く必要もなくなり、コードもスッキリするのではないでしょうか

## Example 3

今度はトレーニングも兼ねて、`validateWith()`がどのような高階関数を引数にもつ拡張関数になるか考えてみましょう

あるベージがあり、クレジットカードの情報を入力するページがあったとして、
その入力完了時に、以下のような情報の入力情報の妥当性チェックを行いたいとします

```Kotlin
val notEmpty: (String) -> Boolean = { !it.isEmpty() }
val atLeastFour: (String) -> Boolean = { it.length() > 4 }
val fourDigits: (String) -> Boolean = { it.matches("\\d{4}")}
val validCreditCard: (String) -> Boolean = { luhnCheck(it) }

firstName.validateWith(notEmpty)
lastName.validateWith(notEmpty)
userName.validateWith(atLeastFour)
pin.validateWith(fourDigits)
creditCard.validateWith(validCreditCard)
```

無駄なく書こうとすれば、こうでしょうか

```Kotlin
val notEmpty: (String) -> Boolean = { !it.isEmpty() }

firstName.validateWith(notEmpty)
lastName.validateWith(notEmpty)
userName.validateWith { it.length() > 4 }
pin.validateWith { it.matches("\\d{4}")}
creditCard.validateWith { luhnCheck(it) }
```

すると `validateWith` はどうなるでしょうか...!?

 :
 :
 :
 :
 :
 :
 :
 :
 :

では正解です
 
```Kotlin
// Stringの場合
fun String.validateWith(body:(String) -> Boolean): Boolean {
    return body(this)
}

// EditTextの場合
fun EditText.validateWith(body:(String) -> Boolean): Boolean {
    return body(this.text.toString())
}
```

ここでの`this`は、それぞれの拡張もとクラスインスタンスを指す、ということに注意してください

# Inline function

インライン関数は、functionのように見えますが、
コンパイル時にその箇所に直接コードが挿入されます

実行時の動きは変わらないように見えますが、
内部動作としては関数コール分が省けるのでパフォーマンスがあがるそうです

イメージ

```Kotlin
fun testPrint() {
    println("testPrint!")
}

println("pre call testPrint")
testPrint()
println("did call testPrint")
```

こう書くと

```
 1. call println("pre call testPrint")
 2. call testPrint()
 3. call println("testPrint!")
 4. call println("did call testPrint")
```

こんな感じですが、inlineを使うと、こうなると

```Kotlin
inline fun testPrint() {
    println("testPrint!")
}

println("pre call testPrint")
testPrint()
println("did call testPrint")
```

```
 1. call println("pre call testPrint")
 2. call println("testPrint!")
 3. call println("did call testPrint")
```

このケースだと恩恵をあまり感じなさそうですが、
たとえばこのtestPrint()をforループ内で読んでいるとどうでしょうか？

とはいえ、通常の開発ではあまりフィーチャーされることはなさそうです。
自分のような下っ端には必要なさそうです。はい。

## Example 1

たとえば、エルビス演算子 `?:` の後ろに書くものを想像します
実はこの後ろには１行しか処理が書けません

```Kotlin
sth?.let {
    // NonNull case
} ?: { // DOES NOT WORK!!
    // Null case
}
```

しかしインライン関数を使うと複数行にわたって書くことが可能です
例えばnullだったときの処理をまとめて書きたいときに便利です

```Kotlin
inline fun guard(body: () -> Unit) = body()
```

```Kotlin
val sth = intent.getStringExtra("SOMETHING")

sth?.let {
    // NonNull case
} ?: guard {
    // Null case
}
```

コメント欄にご指摘いただきましたが、
このレベルであれば `run` を使うことも可能です
（runも実はinline関数です）

というかinline関数である必要も実はありません
**つまり、この例は全然うまくない！笑**

```Kotlin
sth?.let {
    // NonNull case
} ?: run {
    // Null case
}
```

## Example 2

AndroidのNotificationを考えてみましょう
通知するのにBuilderを取得して設定して...面倒ですよね
そんなときはサクッとインライン関数をかいちゃうと便利です

```Kotlin
inline fun notification(context: Context,
        func: Notification.Builder.() -> Unit): Notification {
    val builder = Notification.Builder(context)
    builder.func()
    return builder.build()
}
```

```Kotlin
val n = notification(context)
    setContentTitle("Hi")
    setSubText("Hello")
}
```

# おまけ

お気づきの方もいらっしゃるかと思いますが、
apply, filter系の便利functionはすべてインライン関数やExtensionを使っています

なのでもちろん私たちも、プロジェクトによってよく使われる処理を
インライン関数やExtensionにすることによって、
よりメンテナンス性の高いコードを書くことが可能になります

わくわくしてきません？

# 参考

http://qiita.com/ngsw_taro/items/d29e3080d9fc8a38691e
https://www.youtube.com/watch?v=A2LukgT2mKc
http://hydrakecat.hatenablog.jp/entry/2015/12/08/Kotlin_Inline_Functions