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にすることも可能です。

blog.jetbrains.com