Javaで書いてたAndroidエンジニアが初めてKotlinで書いてみた

この記事は[Kotlin Advent Calendar 2016](http://qiita.com/advent-calendar/2016/kotlin)の最終日の投稿です。
前日はrabitarochanさんの[Kotlin Compiler Plugin (kotlin-allopen) を追いかける](http://rabitarochan.hatenablog.com/entry/2016/12/24/235955)でした。
初日はngsw_taroさんの[Kotlin2016まとめ](http://taro.hatenablog.jp/entry/2016/12/01/074754)でした。

# はじめに
私自身は2015年の3月ごろからKotlinでのAndorid開発を始めましたので、タイトルに反してますが、Kotlin歴は約2年ぐらいです。また、去年は以下のような記事を書きました。

* [2016年、KotlinでAndroid開発する方へ](http://qiita.com/satorufujiwara/items/871c5b7b66c7691d82a8)

2016年はKotlinの記念すべきver1.0のリリースの年でしたが、チームの[マイクロサービスの一つでもKotlinが使われ](http://blog.stormcat.io/entry/kotlin-with-spark)たり、新規のサービスのいくつかはKotlinで開発され、Android研修合宿でも参加者の半数がKotlinを選択するなど、社内的にもKotlinが盛り上がった一年でした。

この記事ではその社内で行った研修合宿において、今までJavaで書いていたAndroidエンジニアに独学でKotlinで書いてもらって、その後コードレビューで「こうすればもっとKotlinっぽくなるかも？」という観点で指摘した事項をまとめました。
Kotlinは様々な書き方が出来るので、人やチームによってルールは違うとおもいますが、この記事においては、「より記述量を減らす」観点になっているかと思います。
これからKotlinでAndroidを書こうと思っている方の参考に少しでもなれば幸いです。

# Javaで書いてたAndroidエンジニアが初めてKotlinで書いてみた

コードレビューの前後のコードの比較を載せます。

## getter/setter

Javaだとfieldにgetterやsetterを作ったりしますが、Kotlinのクラスには基本的にはfieldはなく、[property](https://kotlinlang.org/docs/reference/properties.html)を用います。

Before

```Kotlin
class MyClass {
   private var size : Int = 0

   fun getSize() {
       return size
   }
}
```
After

```Kotlin
class MyClass {
   var size : Int = 0
}
```
Kotlinのpropertyはgetter/setterを自由に変更できるので、以下のような使い方もできます。

```Kotlin
class MyClass {
    val list = mutableListOf<String>()
    var size = 0
        get() = list.size
        private set
}
```

## Constructor

Kotlinはprimary constructorの定義、プロパティの定義をクラス宣言の箇所にまとめて[記述する](https://kotlinlang.org/docs/reference/classes.html)ことができます

Before

```Kotlin
class Person {
    val firstName: String
    val lastName: String
    private var age: Int

    constructor(firstName: String, lastName: String, age: Int) {
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
    }
}
```

After

```Kotlin
class Person(val firstName: String, val lastName: String, private var age: Int) {

}
```

## const

Kotlinには[Compile-Time constants](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants)のための`const`という修飾句があります。

Before

```Kotlin
class MyClass {
    val TOKEN_KEY = "ACCESS_TOKEN_KEY"
}
```

After

```Kotlin
class MyClass {
    companion object {
        const val TOKEN_KEY = "ACCESS_TOKEN_KEY"
    }
}
```

## listOf, mutableListOf

Kotlinの標準関数には[listOf](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html)、[mutableListOf](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-list-of.html)という関数が用意されています。

Before

```Kotlin
fun getList(): List<String> {
    val list: MutableList<String> = ArrayList()
    list.add("value1")
    list.add("value2")
    return list
}
```
After

```Kotlin
fun getList(): List<String> {
    return listOf("value1", "value2")
}
```

```Kotlin
fun getList() = listOf("value1", "value2")
```

## Pair

Kotlinには[Pair](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/)というクラスがあり、任意のクラスの二つの値のセットを持つことができます。
さらに[`to`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html)という関数があり、これを用いると`Pair`の生成が簡単に行えます。

Before

```Kotlin
val params : List<Pair<String, Int>> = listOf(Pair("a", 1), Pair("a", 2))
```

After

```Kotlin
val params = listOf("a" to 1, "a" to 2)
```
`to`は[`infix`](https://kotlinlang.org/docs/reference/functions.html#infix-notation)がついている拡張関数ですので、上のような表記が出来ます。
Pairは以下のような使い方も出来ます。

```Kotlin
val (k, v) = "a" to 1
v == 1 // true

val map = mapOf("a" to 1, "b" to 2)
map["a"] == 1 // true
```

## Data Class

Entityなどは[Data Class](https://kotlinlang.org/docs/reference/data-classes.html)として定義するのが良いでしょう。

```Kotlin
data class User(val name: String, val age: Int)
```

## lazy

Delegates propertyの[`lazy`](https://kotlinlang.org/docs/reference/delegated-properties.html#lazy)を用いることで、propertyをNon-nullかつvalにすることができます。

Before

```Kotlin
var webView: WebView? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail)
  
    webView = findViewById(R.id.webView) as WebView
    webView?.setWebViewClient(WebViewClient())
    webView?.settings?.javaScriptEnabled = true
    webView?.loadUrl("https://kotlinlang.org/")
}
```

After

```Kotlin
val webView by lazy {
    (findViewById(R.id.webView) as WebView).apply {
        setWebViewClient(WebViewClient())
        settings?.javaScriptEnabled = true
    }
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail)
    webView.loadUrl("https://kotlinlang.org/")
}
```

上記のような用途であれば[kotterknife](https://github.com/JakeWharton/kotterknife)を用いるのが良いかもしれません。用いる際は[Retained Fragmentに関するissue](https://github.com/JakeWharton/kotterknife/issues/5)に気をつける必要があります。

## Smart Cast / Safe Cast

Castを用いる必要がある場面では、[Smart Cast](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts)や`as?`による[Safe Cast](https://kotlinlang.org/docs/reference/typecasts.html#safe-nullable-cast-operator)を用いることで簡潔に書けます。

Before

```Kotlin
if (recyclerView?.itemAnimator is SimpleItemAnimator) {
    (recyclerView?.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
}
```

After (Smart Cast)

```Kotlin
recyclerView?.itemAnimator?.let {
    if(it is SimpleItemAnimator) it.supportsChangeAnimations = false
}
```

After (Safe Cast)

```Kotlin
(recyclerView.itemAnimator as? SimpleItemAnimator)?.run {
    supportsChangeAnimations = false
}
```

## kotlin.collections

[kotlin.collections](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index.html)のパッケージには多くの便利な拡張関数が用意されています。

Before

```Kotlin
fun getUrlWithQueryParams(baseUrl: String, param: List<Pair<String, String>>): String {
    var url: String = baseUrl
    var i: Int = 0
    for (pair in param) {
        if (i == 0) {
            url += "?"
        } else {
            url += "&"
        }
        url += (pair.first + "=" + pair.second)
        i++
    }
    return url
}
```

After

```Kotlin
fun getUrlWithQueryParams(baseUrl: String, params: List<Pair<String, String>>) =
params.foldIndexed(baseUrl, {i, url, param -> "$url${if (i == 0) '?' else '&' }${param.first}=${param.second}"}) 
```

# 最後に

Kotlinで開発を始めてから、[「Kotlin」でのTwitter検索](https://twitter.com/search?f=tweets&vertical=default&q=kotlin)をずっと見続けてますが、この1年はKotlinが広く普及した1年でもう至るところで普通に使われだしたな、という印象です。
2017年はもっと盛り上がるでしょう！

今年も一年お疲れ様でした。