Java/Kotlin混合プロジェクトで気をつけていること。
弊社Slackの#eureka-kotlinからの転載シリーズ。 プライベートではすべてKotlinでコードを書いているのであまり気にすることがなかったのですが、pairsはJava/Kotlin混合で成り立っているのでKotlinで書いたコードがJavaからどう見えるのかを気にすることがたまにあります。 すべてを網羅しているわけではありませんが、いくつか書いてみました。
Companion object != Static
Kotlinにはstaticメソッドやstaticフィールドはありませんが、これらと同等の役割を持ったcompanion object
が存在します。
fun KotlinFragment: Fragment() { companion object { fun newInstance(...): KotlinFragment { ... } } }
しかしこれをJavaから利用するには以下のようにする必要があります。
KotlinFragment.Companion.newInstance(...);
これはいまいちですね。Javaからの利用が想定される場合には@JvmStatic
アノテーションを利用します。
fun KotlinFragment: Fragment() { companion object { @JvmStatic fun newInstance(...): KotlinFragment { ... } } }
KotlinFragment.newInstance(...);
Property != Field
Kotlinで定義したPropertyはJavaからはアクセサを通して利用することになります。
class Kotlin { val bar = "bar" }
kotlin.getBar();
これをJavaからFieldとして扱うためには@JvmField
を利用します。
class Kotlin { @JvmField val bar = "bar" }
kotlin.bar;
高階関数
Javaでは関数は第一級オブジェクトではありません。 関数を引数に取るKotlinの関数をJava8未満から利用する場合には、匿名クラスを渡す必要があります。
class Kotlin { fun higherOrder(func: ()->Unit) { ... } }
kotlin.higerOrder(new Function0<Unit>() { @Override public Unit invoke() { return null; } });
関数を返すKotlinの関数であれば、FunctionNが返ってきます。
class Kotlin { fun higherOreder(): ()->Unit { ... } }
Function0<Unit> func = kotlin.higerOrder();
予約語
KotlinでJavaの予約後を使ってしまうと、Javaから呼び出すことができません。
kotlin.final()
JavaでKotlinの予約後を使った場合、Kotlinから呼び出すことはできますが扱いにくいです。
java.`is`()
open
これはJavaからの利用に限った話ではありませんが、Kotlinのクラス、関数はopen
キーワードをつけなければすべてJavaでいうfinal
です。
テストを書く際にmockitoを使ってKotlinクラスをモックしようとしても、継承/オーバーライドすることができません。
mockitoを利用する場合にはモック対象にopen
キーワードをつけて継承/オーバーライド可能にしておきましょう。
Kotlin 1.0.6以降であればAll Open
アノテーションを定義することで一括ですべてをopenにすることも可能です。