fkm blog

software開発に関することを書いていきます

Google I/O 2019: What's New in Kotlin on Android, 2 Years In

youtu.be

KotlinがAndroidの公式言語になって2年。決定自体は3.5年前ほど前。コミュニティとかに聞いてもKotlinが好まれていた。

Kotlin foundation

Kotlin言語を保護/推進/高度にするためにJetbrainとGoogleによって作られた。ボードメンバーは - 2人がJetbrain - 2人がGoogle - 1人がそれ以外

言語の設計。また言語の破壊的変更のコントロールとかも。より詳しいことは

https://kotlinlang.org/foundation/kotlin-foundation.html で。

ここからはデモ。

when に関しては、次のように when 内部でのみ有効な書き方がある。 responsewhen の中だけ有効。

when (val response = calculateROI(years)) {
    50 -> println("Too long")
    5 -> println("Bargain")
    else -> println("Can't handle $response")
}

ある機能やクラスが実験的(experimental)であるというアノテーションが作れる。例えばNewAPIですよーというアノテーション

@Experimental
annotation class NewAPI

@NewAPI
class MicroserviceAPI

fun main() {
    val microserviceAPI = MicroserviceAPI() // コンパイルエラー : これは実験的なAPI
}

警告にしたい場合は、レベルをつけてwarningにする。

@Experimental(level = Experimental.Level.WARNING)
annotation class NewAPI

次はcontractについて。通常、nullチェックをした場合、その後はnon-nullとして扱うことができる。この機能をスマートキャストと言う。

fun printLength(s: String?) {
    if (s != null) {
        println(s.length)
    }
}

ここで、次のように != ではなく、メソッドで判別した場合はどうなるだろう?

fun String?.notNull(): Boolean {
    return this != null
}

fun printLength(s: String?) {
    if (s.notNull()) {
        println(s.length) // コンパイルエラー。sはnullable
    }
}

これだと嬉しくない。ここで登場するのがcontract。 true を返した場合、 this はnullでないよとお知らせしている。

import kotlin.contratcs.contract

fun String?.notNull(): Boolean {
    contract {
        returns(true) implies (this@notNull != null)
    }
    return this != null
}

fun printLength(s: String?) {
    if (s.notNull()) {
        println(s.length) // 今回はコンパイルエラーにならない。
    }
}

しかしこのcontractはexperimentalなAPIなので、そのままでは使えない。なので notNull() にexperimentalなAPI使ってますよのアノテーションをつける。

import kotlin.contracts.ExperimentalContracts
import kotlin.contratcs.contract

@UseExperimental(ExperimentalContracts::class)
fun String?.notNull(): Boolean {
    contract {
        returns(true) implies (this@notNull != null)
    }
    return this != null
}

マルチプラットフォーム

例えばプラットフォーム名といった、各プラットフォーム固有の実装を作りたい場合は expectactual を使う。

共通コード(common)では、 次のように expect を用意し、使う。

expect object Platform {
    val name: String
}

fun hello(): String = "Hello from ${Platform.name}"

もちろん実装は各プラットフォームで作らないといけない。例えばJVM用であれば次のように作る。

actual object Platform {
    actual val name: String = JVM"
}

未実装のプラットフォームがあった場合はコンパイルエラー。

AndroidとKotlin

実際に実行されるのはバイトコードなので、そんなにできることはないけど、デバッグ用の機能がAndroid Q(多分)に入っている。例えばインライン関数とか。

Jetpackのライブラリはコルーチンに対応。詳細は他のセッションにて。

KotlinプラグインAndroid Studioの一部になった(だいぶ前な気もするけど)。なのでAndroid Studioのリリース前に動作するかチェックされている。また、Android特有のリファクタリングにも対応した。例えばレイアウトXMLのファイル名を変更したとき、 R.layout.xxxx で参照している部分も変更するとか。

LintもKotlinサポートになった。またテンプレート(例えばフラグメントの追加とか)もKotlinになった。R8もKotlin特有の最適化をやるようになっている。

ドキュメントはKotlinとJavaの両方で見れる。

Googleでは?

Googleの内部で使われているアプリでもKotlinが使われている。例えば地図やオフィスの位置を表示するアプリとか。

GoogleドライブやGoogleホームアプリとかではKotlinが使われている。

直近6ヶ月で見ると、16%のアクティブに開発されているアプリがKotlinを使っている。去年のI/Oからだと5倍に増えている。トップ1000アプリだと44%のアプリが使っている。

Kotlin First

Kotlinを使っての開発にみんな満足している。調査によるとKotlinを使っているエンジニアのほうが25%も幸せであった。

Kotlin Firstとはどういうことか?Javaをやめるわけではなく、一部のもの(オンライントレーニングやサンプル)はKotlin firstで、Javaはベストエフォートになる。またマルチプラットフォームJetpack ComposeはKotlinのみになる。

Switchすべき?プロジェクトの状態による。リリースが1週間後に迫っているようなプロジェクトでは当然だがスイッチすべき時じゃない。次の開発サイクルに入るタイミングで導入してみるのがよさそう。

もちろんKotlin導入にはトレードオフがある。(学習しやすいとはいえ)Kotlinの学習曲線については気にする必要がある。最初Kotlinを書いてみると、JavaっぽいKotlinコードになる。3〜6週間して、ようやくKotlinらしいコードがかけるようになる。

Ongoing Kotlin work

Kotlin everywhere

https://kotl.in/everywhereを見てね