Java開発者に送るKotlinとの相互運用Tips

# KotlinコードをJavaから呼び出すとき
## デフォルト引数

Kotlinのデフォルト引数付き関数をJavaから扱いたい場合、全ての引数を指定しなければなりません。
ですが、関数に`@JvmOverload`アノテーションを付加すると自動的にオーバーロードメソッドが生成されます。

```kotlin
// Kotlin
class OverloadSample {
    @JvmOverloads // アノテーションをつけると、Javaから呼び出し可能なオーバーロードメソッドが生成される
    fun test(arg1: Boolean = true, arg2: Int = 1, arg3: String = "true") : Boolean {
        return arg1 && arg2 == 1 && arg3 == "true"
    }
}
```

Javaからの呼び出しコードを実装してみます。

```java
// Java
OverloadSample os = new OverloadSample();
os.test(true, 1, "true");
os.test(true, 1);
os.test(true);
```

## トップレベル関数、プロパティ
クラスに属さないトップレベルのKotlin関数をJavaから呼び出す方法です。
Kotlinのトップレベル関数は
`ソースファイル名+Kt`という名前のクラスが生成され、
そのクラスのstatic関数へコンパイルされます。

```kotlin
// Utility.kt
fun doSomething() {
    // Do something
}
```

```java
// Java
UtilityKt.doSomething();
```

上記の`ソースファイル名+Kt`というクラス名を変更したい場合は`@JvmName`アノテーションを使います。このアノテーションはパッケージに記述しまし。

```kotlin
// Utility.kt
@file: JvmName("Util")
package com.sample

fun doSomething() {
    // Do something
}
```

```java
// Java
Util.doSomething();
```

## 拡張関数

拡張関数はトップレベル関数と同じく、`ソースファイル名+Kt`という名前のクラスのstatic関数としてコンパイルされます。Javaから呼び出す場合は、thisとなるオブジェクトが第一引数となります。

```kotlin
// StringUtility.kt
fun String.join(otherString: String) : String {
    return this + otherString
}
```

```java
// Java
StringUtilityKt.join("Hello, ", "World!");
```

## objectクラス

objectクラスをJavaからみると、`INSTANCE`というstaticフィールドを持ったクラスとなります。objectクラスのプロパティか関数にアクセスするには、この`INSTANCE`を経由します。

```kotlin
// Kotlin
object LogUtil {
    fun debug(log: String) {
        //
    }
}
```

```java
// Java
LogUtil.INSTANCE.debug("completed!");
```

# JavaコードをKotlinから呼び出すとき
## プラットフォーム型

Java関数の戻り値をKotlinコードで受ける場合など、
その戻り値がnull許容型か否かは`@NonNull`と`@Nullable`の
アノテーションで判断されます。

```Java
// Java
public class Sample {

    @NonNull
    String getString1() {
        return //
    }

    @Nullable
    String getString2() {
        return //
    }
}
```

Kotlinで呼び出すと以下のようになります。

```kotlin
// Kotlin
val sample = Sample()
val str1 = sample.string1 // 非null許容型
val str2 = sample.string2 // null許容型
```

ただし、`@NonNull`や`@Nullable`のアノテーションは
コンパイル時に強制力を持つものではないので注意が必要です。

では、アノテーションをつけない場合は...

```java
// Java
public class Sample {
    // アノテーション無し
    String getString3() {
        return  //
    }
}
```

Kotlinから呼び出してみます。

```kotlin
// Kotlin
val sample = Sample()
val str3 = sample.string3 // String!
```

`String!`という型になります。
この`!`のついた型をプラットフォーム型といいます。

null許容型でも非null許容型でも扱える、どっちも型です。
Nullであるか否かを開発者に委ねる考え方です。

```kotlin
// Kotlin
val sample = Sample()
val str = sample.string3
val length = str.length // 非null許容型として扱う
val char = str?.get(0) // null許容型として扱う
```

## static関数、staticフィールド

何らかの理由でstatic関数やフィールドが必要な状況があり得ます。
[例えば...](https://developer.android.com/reference/android/os/Parcelable)

Kotlinでstaticっぽく使える`companion object`。
ここでアノテーションを使うと、Javaのstaticとしてコンパイルされます。

```kotlin
// Kotlin
class Sample {
    companion object {

        @JvmField // staticフィールドへのコンパイルを指定するアノテーション
        var TAG: String = "Sample"

        @JvmStatic // static関数へのコンパイルを指定するアノテーション
        fun tag(): String {
            return "Sample"
        }
    }
}
```

```java
// Java
String tag = Sample.TAG;
tag = Sample.tag();
```

## SAM変換

特定の条件下において、
Javaのインターフェースを実装したクラスをラムダ式で作ることができます。

```kotlin
val executor: ThreadPoolExecutor

// executeメソッドの引数にはRunnableを実装したオブジェクトを渡す
executor.execute(object: Runnable{
    override fun run() {
        //
    }
})

// SAM変換により、ラムダ式で表現可能！
executor.execute { 
    //
}
```

KotlinでSAM変換が有効となる条件は以下です。

* Javaで宣言されたインターフェースであること  
* 抽象メソッドが1つだけのインターフェースであること

Kotlinには適切な関数型が存在するのでKotlinで宣言したインターフェースではSAM変換は有効になりません