Kotlin 勉強メモ

Kotlin のコードを書いててよくわからなかったところや、ハマったところとかのメモ。
今後適宜追記していくかも。

基本的な文法とかは、 @k5n さんが以下の翻訳記事を書かれているのでそちらを参照ください。

- [３０分で覚えるKotlin文法 - Qiita](http://qiita.com/k5n/items/cc0377b75d8537ef8a85)
- [Kotlin文法 - 基本 - Qiita](http://qiita.com/k5n/items/acfaff8b56faf57971f7)


# Kotlin とは
JetBrains というチェコの会社が開発したプログラミング言語。
JetBrains は、 IntelliJ IDEA を開発している会社でもある。

- JVM 上で動作する。
- 静的型付け言語。
- オープンソース(Apache License 2)。

# 環境
## OS
Windows 7

## Java
1.8.0_74

# Hello World
JDK のインストールは割愛。

## コンパイラをインストールする
[GitHub の Release](https://github.com/JetBrains/kotlin/releases/tag/build-1.0.0) からコンパイラを落とせる。

`kotlin-compiler-x.x.x.zip` をダウンロードしてきて、任意のフォルダに解凍する。
`bin` の下にパスを通したら、インストールが上手くいっているか確認するため、以下のコマンドを実行する。

```tex
> kotlin -version
Kotlin version 1.0.0 (JRE 1.8.0_74-b02)
```

## 実装する
```kotlin:hello.kt
fun main(args : Array<String>) {
    println("Hello Kotlin!!")
}
```

- 拡張子は `.kt` で作成する。

## コンパイルする
```text
> kotlinc hello.kt
```

- `kotlinc` コマンドでコンパイルできる。

### コンパイルで出力されるファイル
```text
> dir /b
hello.kt
HelloKt.class

> javap HelloKt.class
Compiled from "hello.kt"
public final class HelloKt {
  public static final void main(java.lang.String[]);
}
```

- コンパイルが完了すると、 `class` ファイルが出力される。
- `HelloKt` というクラスと `main` メソッドが生成されている。

## 実行する
```text
> kotlin HelloKt
Hello Kotlin!!
```

- `kotlin` コマンドで実行する。
- 実行するメインクラスとして `HelloKt` を指定する。
    - `-classpath(-cp)` など、 `java` コマンドと同じ感じで実行する。

# いろいろな実行方法
## jar にまとめる
```text
> kotlinc -d hello.jar hello.kt

> kotlin -cp hello.jar HelloKt
Hello Kotlin!!
```

- `-d` オプションで出力先の `jar` ファイル名を指定すると、コンパイル結果が `jar` ファイルにまとめられる。

## Kotlin のランタイムも jar にまとめる
```text
> kotlinc -d hello.jar -include-runtime hello.kt

> dir
2016/02/28  13:30    <DIR>          .
2016/02/28  13:30    <DIR>          ..
2016/02/28  13:30           799,490 hello.jar
2016/02/28  13:23                68 hello.kt

> java -jar hello.jar HelloKt
Hello Kotlin!!
```

- `-include-runtime` オプションを指定すると、 Kotlin のランタイムも一緒にまとめた `jar` ファイルが生成される。
    - サイズは `800KB` 弱ほど（結構軽いと思う） 。
- なので、普通に `java` コマンドで実行できる（Kotlin をインストールしていない環境でも動かせる）。

## スクリプトファイルとして実行する
```kotlin:hello.kts
println("Hello Kotlin!!")
```

```text
> kotlinc -script hello.kts
Hello Kotlin!!
```

- スクリプトファイルとして実行することもできる。
- ファイルの拡張子を `.kts` にする。
- `kotlinc` コマンドに `-script` オプションを指定して実行する。

## Gradle でコンパイルする
```groovy:build.gradle
buildscript {
    repositories {
        mavenCentral()
    }
 
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.0"
    }
}

apply plugin: 'kotlin'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.0"
}
```

- Gradle 用のプラグインとして `org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.0` を読み込む。
- `kotlin` プラグインを使用する。
- 依存関係として `org.jetbrains.kotlin:kotlin-stdlib:1.0.0` を追加する。

```text:フォルダ構成
|-build.gradle
`-src/main/kotlin/
  `-hello.kt
```

- `src/main/kotlin` の下にソースコードを入れる。

```kotlin:hello.kt
fun main(args : Array<String>) {
    println("Hello Kotlin!!")
}
```

```text:コンパイル
> gradle jar

> kotlin -cp build\libs\hello.jar HelloKt
Hello Kotlin!!
```

- とりあえず、 `jar` コマンドで `jar` ファイルを生成できる。


# 文法とか
## プライマリコンストラクタを `private` にする
```kotlin
class Hoge private constructor() {
}
```

## オブジェクトの比較
```kotlin
fun main(args: Array<String>) {

    val a = Hoge("a")
    val b = Hoge("a")

    println(a === b)
    println(a == b)
}

class Hoge(val name: String) {

    override fun equals(o: Any?): Boolean {
        if (this === o) return true
        if (!(o is Hoge)) return false

        println("equals()!!")

        return this.name == o.name
    }
}
```

```text:実行結果
false
equals()!!
true
```

- 参照するオブジェクトが同じかどうかは `===` で調べられる。（Java でいう `==`）。
- Kotlin の `==` は、 `equals()` メソッドが裏で呼びだされている。

## Java で定義されたメソッドなどの名前が Kotlin の予約語だった場合
```java
public class Hoge {
    public boolean is(Hoge hoge) {
        return false;
    }
}
```

```kotlin
fun main(args: Array<String>) {
    val hoge = Hoge()
    val fuga = Hoge()

    hoge.`is`(fuga)
}
```

- `is` は Kotlin では予約語なので、そのままだとコンパイルエラーになる。
- メソッド名を `` ` `` （バッククォート）で括ることで、 Kotlin でも `is` などの予約語になっているメソッドを使えるようになる。

# 文字列
## 文字列内で $ を出力する
```kotlin
fun main(args : Array<String>) {
    val a = "hoge"
    
    println("$")
    println("$a")
    println("${'$'}a")
}
```

```text:実行結果
$
hoge
$a
```

- 文字列の中に `$<変数名>` で、変数の値を埋め込むことができる。
- しかし単純に `$` を出力したい場合で、かつその後ろに文字があると変数と誤認識されてしまう。
- 単純に `$` と出力したい場合は、ちょっと面倒だけど `${'$'}` とする。


# Class オブジェクトの取得
## 変数から取得
```kotlin
fun main(args: Array<String>) {
    val clazz: Class<*> = "text".javaClass

    println("clazz = $clazz")
}
```

```text:実行結果
clazz = class java.lang.String
```

## クラス名から取得
```kotlin
fun main(args: Array<String>) {
    val clazz: Class<*> = String::class.java

    println("clazz = $clazz")
}
```

```text:実行結果
clazz = class java.lang.String
```

**参考**

- [getClass() | Calling Java from Kotlin - Kotlin Programming Language](https://kotlinlang.org/docs/reference/java-interop.html#getclass)


# 可変長引数
## デフォルト値を指定する
```kotlin
fun function(vararg arguments : String = arrayOf("a", "b", "c")) {
    println("arguments=${arguments.joinToString(", ")}")
}

fun main(args : Array<String>) {
    function()
}
```

```text:実行結果
arguments=a, b, c
```

- `arrayOf()` でデフォルト値を設定できる。

## 名前付き引数で値を渡す
```kotlin
fun function(vararg arguments : String) {
    println("arguments=${arguments.joinToString(", ")}")
}

fun main(args : Array<String>) {
    function(arguments = "foo")
    function(arguments = *arrayOf("foo", "bar"))
    
    // 以下はコンパイルエラー
//    function(arguments = "foo", "bar")
//    function(arguments = ("foo", "bar"))
//    function(arguments = arrayOf("foo", "bar"))
}
```

```text:実行結果
arguments=foo
arguments=foo, bar
```

- 単一なら、その値をそのまま渡す。
- 複数の値を渡したい場合は、先頭にアスタリスク `*` を付ける。

# 配列
## サイズを指定して初期化
```kotlin
import java.util.Arrays

fun main(args: Array<String>) {
    val intArray = IntArray(3)
    println("intArray=${Arrays.toString(intArray)}")
    
    val array = Array(3, {i -> "init-$i"})
    println("array=${Arrays.toString(array)}")
}
```

```text:実行結果
intArray=[0, 0, 0]
array=[init-0, init-1, init-2]
```

- プリミティブ配列の場合は、コンストラクタ引数でサイズを指定すれば、そのサイズの配列が生成される
- オブジェクト配列（`Array`）の場合は、第二引数に各要素の初期値を生成して返すラムダ式を渡す
    - ラムダ式にはその要素のインデックスが順次渡される


# 演算子オーバーロード
```kotlin
class Hoge(private val i: Int) {
    operator fun plus(other: Hoge) = Hoge(this.i + other.i)
    override fun toString() = "Hoge(${this.i})"
}

fun main(args: Array<String>) {
    println(Hoge(10) + Hoge(21))
}
```

```text:実行結果
Hoge(31)
```

- 所定の名前のメソッドを定義して `operator` で修飾すると、演算子オーバーロードができるようになる

メソッドと演算子の対応は公式ドキュメントの [こちら](https://kotlinlang.org/docs/reference/operator-overloading.html) を参照。

# ラムダ・関数
## 関数インターフェースにラムダ式を渡す
```java:Foo.java
public class Foo {

    public static void method(Runnable runnable) {
    }
}
```

```kotlin
fun main(args: Array<String>) {
    Foo.method { println("Hello") }
    function(Runnable {println("Hello")})
}

fun function(runnable: Runnable) {
}
```

- 引数が関数型インターフェース（抽象メソッドを１つだけ持つインターフェース）の場合、
    - メソッドが Java ソースで定義されたものの場合は、引数と戻り値の型が一致するラムダ式を渡すことができる。
        - SAM(Single Abstract Method) 変換と呼ばれる。
    - メソッドが Kotlin ソースで定義されたものの場合は、ラムダ式の前に型名を明示しなければならない。
- ただし、インターフェースが Kotlin ソースで定義されたものだと、ラムダ式は渡せないっぽい。
    - おとなしく関数型で型を宣言するしかなさそう。

```kotlin
fun main(args: Array<String>) {
    val f : Runnable = Runnable {println("Hello")}
}
```

- 変数に代入する場合も同様。

**参考**

- [java - Lambda expressions in Kotlin - Stack Overflow](http://stackoverflow.com/questions/26507099/lambda-expressions-in-kotlin)
- [Kotlinでリスナーやコールバックをスッキリと書く【関数リテラルとSAM変換】 - Qiita](http://qiita.com/RyotaMurohoshi/items/01b370f34a4bf96f5c39)


## Kotlin のオブジェクトに定義したメソッドなどを Java から参照する
```kotlin
object Hoge {
    fun method() {}
}
```

```java
public class Main {

    public static void main(String[] args) {
        Hoge.INSTANCE.method();
    }
}
```

- 単純なクラスメソッドではなかった。
- `INSTANCE` とかいうフィールドを経由するっぽい。
- コンパニオンオブジェクトの場合は、 `Companion` というフィールドを経由する。

```kotlin
class Hoge {
    companion object {
        fun hello() = println("Hello")
    }
}
```

```java
public class Main {

    public static void main(String[] args) {
        Hoge.Companion.hello();
    }
}
```

## 関数（ラムダ式）のレシーバーの型を指定する
```kotlin
fun func(lambda : String.() -> Unit) {
    "Receiver".lambda()
}

fun main(args : Array<String>) {
    func {
        println("this=$this")
        println(substring(0, 3))
    }
}
```

```text:実行結果
this=Receiver
Rec
```

- 関数の型の前に `<レシーバーの型>.` をつけると、その関数を実行するときのレシーバーの型を指定できる。
- その関数を実行している間、その中の `this` はレシーバーを指すようになる。
- Groovy の `delegate` みたいな感じ。
- DSL 作るときに使いそう。

# アノテーション
## `@Deprecated`
Kotlin の `@Deprecated` は、独自のアノテーションが用意されている。

```kotlin
fun main(args: Array<String>) {
    hoge()
}

@Deprecated("使うな！！")
fun hoge() {
}
```

Kotlin の `@Deprecated` は、 `message` 属性が必須になっており、なんらかのメッセージを渡す必要がある。

また、 `level` という属性が用意されており、その API を使った場合にコンパイルエラーにさせることができる。

```kotlin
fun main(args: Array<String>) {
    hoge() ★コンパイルエラー
}

@Deprecated(message = "使うな！！", level = DeprecationLevel.ERROR)
fun hoge() {
}
```

`level` を指定しない場合はデフォルトの `DeprecationLevel.WARNING` になるので、コンパイルエラーにはならない。
`DeprecationLevel.ERROR` を指定すると、その API を使用した箇所がコンパイルエラーになる。

`DeprecationLevel.HIDDEN` を指定すると、その API は他のコードから一切参照できなくなる。
`ERROR` との使い分けは、よくわからない。

**参考**

- [Deprecated - stdlib - Kotlin Programming Language](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deprecated/)

# 型引数
## 共変
Java は非変なので、型引数が継承関係になっていても変数の代入はできない。

```java
import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<Integer> integerList = Arrays.asList(1, 2, 3);
        List<Number> numberList = integerList; // ★コンパイルエラー！！

        numberList.forEach(n -> System.out.println(n));
    }
}
```

一方、 Kotlin は読み取り専用なコレクションなら共変になる。

```kotlin
fun main(args: Array<String>) {
    val integerList = listOf(1, 2, 3)
    val numberList: List<Number> = integerList // ★コンパイルが通る！

    numberList.forEach { println(it) }
}
```

```text:実行結果
1
2
3
```

読み書き可能なコレクションだと、コンパイルエラーになる。

```kotlin
fun main(args: Array<String>) {
    val integerList = mutableListOf(1, 2, 3)
    val numberList: MutableList<Number> = integerList // ★コンパイルエラー！！！

    numberList.forEach { println(it) }
}
```

### コンパイラはどうやって読み書き可能か読み取り専用かを判断している？
ところで、コンパイラはどうやってその型が読み書き可能なのか、それとも読み取り専用なのかを判断しているのだろうか？

`kotlin.collections.List` の定義を見ると、以下のようになっている。

```kotlin
public interface List<out E> : kotlin.collections.Collection<E> {
...
```

何やら、型引数に `out` というキーワードが使用されている。

試しに、自作のクラスで `out` を使った型引数を定義してみる。

```kotlin
interface Base<out T> {

    fun get(): T

    fun set(t: T)
}
```

このインターフェースは、以下のようなエラーになってコンパイルできない。

```
Type parameter T is declared as 'out' but occurs in 'in' position in type T
```

「型引数 `T` は `out` （出力）で宣言しているのに、 `in`（入力）の場所に現れているよ！」というエラー内容になっている。

つまり、型引数を `out` で宣言することで、その型を出力専用にできる。
この結果、その型は共変扱いにできるとコンパイラが判断できる、というカラクリになっている（スマートで良いなぁ）。

ちなみに、 `<in T>` とすれば入力専用にもできる。

**参考**

- [Java ジェネリクスのポイント - Qiita](http://qiita.com/pebblip/items/1206f866980f2ff91e77)
- [Java総称型メモ(Hishidama's Java Generics Memo)](http://www.ne.jp/asahi/hishidama/home/tech/java/generics.html#covariant)

# JavaEE
## EJB に DI しようとしたら UninitializedPropertyAccessException が出た場合の対処
```kotlin
package sample.ejb

import sample.cdi.KotlinCdiBean
import javax.ejb.Stateless
import javax.inject.Inject

@Stateless
open class KotlinEjb {

    @Inject
    lateinit private var bean: KotlinCdiBean

    fun hello() {
        this.bean.hello()
    }
}
```

EJB (Stateless Session Bean) に CDI 管理の Bean を `@Inject` でインジェクションしようとしている。
これを実行すると、以下のようなエラーが発生する。

```text:エラーのスタックトレース
StandardWrapperValve[sample.web.SampleApplication]: Servlet.service() for servlet sample.web.SampleApplication threw exception
kotlin.UninitializedPropertyAccessException: lateinit property bean has not been initialized
        at sample.ejb.KotlinEjb.hello(KotlinEjb.kt:14)
```

`lateinit` 指定したプロパティが初期化できなくてエラー、というメッセージが出力されている。

一見すると `bean` フィールドの書きっぷりとか `KotlinCdiBean` の定義とかに問題がありそうだが、実際は<ins> `KotlinEjb` の `hello()` メソッドが `open` になっていないことが原因になっている</ins>。

```diff

@Stateless
open class KotlinEjb {

    @Inject
    lateinit private var bean: KotlinCdiBean

-   fun hello() {
+   open fun hello() {
        this.bean.hello()
    }
}
```

`hello()` を `open` にして再実行すると、エラーは発生しなくなる。

ちなみに、インジェクション先のクラスが EJB ではなく CDI 管理 Bean だった場合は、起動時に以下のようなエラーが発生する（Payara の場合）。

```text:CDI管理Beanのメソッドがopenになっていなかった場合のエラー
org.jboss.weld.exceptions.DeploymentException: WELD-001410: The injection point [BackedAnnotatedField] @Inject private sample.ejb.KotlinEjb.bean has non-proxyable dependencies
        at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:380)
...
Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001437: Normal scoped bean class sample.cdi.KotlinCdiBean is not proxyable because the type is final or it contains a final method public final void sample.cdi.KotlinCdiBean.hello() - Managed Bean [class sample.cdi.KotlinCdiBean] with qualifiers [@Any @Default].
```

ちゃんと 「`final` にするな！」というメッセージを出力してくれる。
（EJB だと、起動はできて実行時にエラーになるうえ、メッセージが直接的でないので原因が分かりにくい！）


# その他
## 親クラスがアクセサメソッドを持つ場合で、サブクラスでフィールドを定義する
```kotlin
open class Parent {
    fun getValue() = "parent"
}

class Child: Parent() {
    private val value = "child"
}
```

こんな実装をすると、 `Child` の方でコンパイルエラーになる。

![kotlin.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/4d1db634-2001-6c1f-c887-9779307e1d4d.jpeg)

以下のように親クラスの `getValue()` を `open` にして、サブクラスで明示的にオーバーライドすればコンパイルエラーは外れる。

```kotlin
open class Parent {
    open fun getValue() = "parent"
}

class Child: Parent() {
    private val value = "child"

    override fun getValue() = this.value
}
```

**参考**

- [spring security - Resolving Accidental Override errors in Kotlin - Stack Overflow](http://stackoverflow.com/questions/32970923/resolving-accidental-override-errors-in-kotlin)



# Eclipse で開発する（おまけ）
※[IntelliJ](http://qiita.com/opengl-8080/items/108102d692b49f804dbd) で開発するのがオススメですが、どうしても Eclipse で Kotlin したい場合のメモ。。。。

## プラグインをインストールする
- マーケットプレイスで `Kotlin` で検索すれば「Kotlin Plugin for Eclipse」というプラグインが出てくるので、これをインストールする。
- インストールが完了したら、「新規作成」から Kotlin 用のプロジェクトを作れるようになる。
- 実行は、 `main` 関数があるファイルを開いて `Ctrl` + `F11` をするか、ソースファイルを右クリックして「実行」→「Kotlin Application」を選択。

## Gradle の Eclipse プラグインで Kotlin 用のプロジェクトにする
```groovy:build.gradle
buildscript {
    repositories {
        mavenCentral()
    }
 
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.0"
    }
}

apply plugin: 'kotlin'
apply plugin: 'eclipse'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.0"
}

eclipse {
    project {
        name = 'kotlin-sample'
        buildCommand 'org.jetbrains.kotlin.ui.kotlinBuilder'
        natures 'org.jetbrains.kotlin.core.kotlinNature'
        linkedResource(
            name: 'kotlin_bin',
            type: '2',
            locationUri: "org.jetbrains.kotlin.core.filesystem:/${name}/kotlin_bin"
        )
    }
    classpath.containers 'org.jetbrains.kotlin.core.KOTLIN_CONTAINER'
}
```

- Eclipse で普通に Kotlin プロジェクトを作ったときの `.project` と `.classpath` を参考に、必要な設定を追加しただけ。
- とりあえず、これで `eclipse` コマンドを実行して Eclipse に取り込めば、 Kotlin プロジェクトとして処理してくれる。
    - `Kotlin Runtime Library` と依存関係で指定している Kotlin のランタイムが重複しているのが少し気になる。