Android向けKotlinのロードマップ
Googleが最近アナウンスした中で最も興味深いニュースはJackコンパイラによりAndroidNでJava8を(限定的に)サポートするという話ではないでしょうか。当然ながら皆様はこれがKotlinのAndroid開発向けのロードマップにどう影響するか興味のあることと思いますのでここで説明させてください。
KotlinのAndroid向けのロードマップ
JetBrainsではKotlinがAndroid開発で優れたツールとなるよう多大な注目を置いています。今後いくつかのバージョン1.0.Xにおけるリリースでは引き続きツール群やライブラリの改善を施していきます。フォーカスは三つのエリアに渡っています。開発ワークフローのスピードアップ、ランタイムライブラリのサイズ削減、ツールサポートの充実化です。
開発ワークフロー
開発ワークフローの高速化のため、KotlinのGradleプラグインはインクリメンタルコンパイルをサポートするようになります。ソースに変更があった場合、モジュール全体ではなく本当に影響のある箇所だけを再コンパイルするためビルド時間を大幅に短縮できます。
続いてAndroidのビルドパフォーマンス改善のためAndroidの新しいJack and Jillツールチェインとのインテグレーションを提供します。 現在のところKotlinの生成するバイトコードのハンドルを妨げる問題(196084 と 203531)がありますが、Googleのチームと連携して問題を解決するか、JetBrainsサイドにて回避策を提供する予定です。それが完了したら、インクリメンタルコンパイル中に変更のあったクラスファイルのみJillを使ってトランスレート出来るようになります。(なおこれまでAndroidサポートでは毎回全てのクラスをトランスレートする必要がありました)。
そしてインスタントランです。現在のところKotlinではコールドスワップしかできず、ウォームとホットスワップをサポートするためにもうしばらく調査が必要です。しかし早急に可能な限りを尽くします。それまでの間、JRebel for Androidを使えばKotlinのホットスワップを行うことが可能です。
ランタイムサイズ
メソッド数を削減してkotlin-stdlibのサイズを縮めるべく、いくらかの改善を施す計画があります。現在のところ7191です:
複数ファイルに渡るファサードクラスのトップレベルファンクションの最適化や、inline-onlyの関数をランタイムバイナリから外すとで数千のメソッド数を削減できる見込みです。
ツールサポート
Kotlin 1.0のAndroidサポートで欠けているものの内一番大きいのがLintチェックでしょう。でもご安心ください。もちろんKotlinのLintチェックのリリース予定があります。既にAndroid Studio 1.5でLintチェックができるよう実装済みで、Kotlin 1.0.2でリリース予定です。そしてAndroid Studio 2.0向けについては現在実装中です。LintチェックはKotlinとJavaコードの共通基盤上に実装しており、今後Android SDKがデフォルトの状態でKotlinサポートできるようこの基盤をAndroid SDKへコントリビュートする予定です。
Android特有のIDEサポート、例えば”New Kotlin Activity”アクション、コードインサイトやナビゲーションなどは少しずつ1.0.xリリースで加えられていきます。
KotlinとJava 8
Java 8がリリースされてしばらく経過しておりますが、Android開発を行っていない開発者でもJava 8よりもKotlinを選択して楽しんでいらっしゃる方々が沢山いらっしゃいあす。Androidが正式にJava8の言語機能をサポートしましたが、KotlinとJavaの選択にどう影響を与えるでしょうか?
まず第一に、Java 8のラムダをAndroidにもたらしますが、Androidのツールチェインがサポートするラムダの既存プラットフォーム(Nリリース以前)サポートはKotlinによるサポートとは重要な違いがあります。違いを理解するため、シンプルなコード例をお見せします:
Kotlin: list.forEach { process(it) }
Java 8: list.forEach(it -> process(it))
Java版はほんの少しだけ長いですが、ここでは目をつぶって水面下で何が起きているか確認しましょう。Javaでは:
- AndroidのJava 8ではラムダはすべて二つのメソッド(コンストラクタとボディ)を持つクラスへとコンパイルされます。アプリケーションのメソッドカウントに影響があります。
- クラスは後にランタイムで繰り返しインスタンス化されます。例えばforEachが呼ばれるたびにインスタンス化されるため、ガベージコレクタへの大きな負担となります。
- インスタンスにアクセスするため、Consumer.acceptの呼び出しに多態コール(polymorphic call)を使いますが、インライン化が出来ないためパフォーマンスへの影響があります。
Kotlinではインライン関数をサポートしており、forEachはその内の1つです。ラムダでインライン関数を使えば関数ボディとラムダはコールサイトにてインライン化されます。結果として:
- ラムダのバイトコードは呼び出すメソッドのバイトコードに直接挿入され、メソッドカウントは増えません。
- コード呼び出しによるオブジェクト生成はなく、ガベージコレクタへの負担もありません。
- 生成されたバイトコードに多態メソッドコールはなく、ランタイムで可能な限りベストなパフォーマンスを引き出します。
つまり、AndroidにおけるJava 8ラムダは必ずしも好きに使って良いものではなく毎回コードのエレガンスさをとるかパフォーマンスをとるかで悩む必要があります。一方でKotlinではそのような妥協は必要ありません。コードを表現する上でベストであれば常にラムダを選んで結構です。
そして、もちろんKotlinはJavaにはない沢山の魅力的な言語機能があります。主なものを少しだけ挙げます:
- null安全機能によりコードで起きるNullPointerExceptionをほぼ防止できる
- プロパティ、プライマリコンストラクタ、データクラスによりコードの定型文を大幅に削減することができる:
data class User(val name: String, val groupId: String = "default")
- 委譲プロパティ(Delegated properties)によりプロパティのgetter/setterに置ける共通のロジックを抽出できる:
val imageData by lazy { loadData(imageFile) }>
そしてKotlinのDSLコンストラクション機能はJavaでは簡単に実現できないフレキシビリティをもたらします。例えばXMLレイアウトをKotlinの抽象化機能をフル活用した埋込DSLにより表現することが可能です。Anko libraryではこのように実現しています:
1
2
3
4
5
6
|
verticalLayout {
val name = editText()
button(“Say Hello”) {
onClick { toast(“Hello, ${name.text}!”) }
}
}
|
ご覧の通り、KotlinはJava 8がJava 6デベロッパにもたらすよりも遙かに大きな生産性をもたらします。そして網羅的なドキュメントやインタラクティブなエクササイズ、Kotlinの基本やAndroid開発向けの本もあり学習は容易です。まだKotlinをお試しでないなら、今こそがお試しください!
[原文]