【Kotlin】@JvmStaticと実行時間

## 1. `object` について
object を理解するには、 **Singleton** というものを知っていなければいけません。
これは、「あるクラスのインスタンスを１つのみにする」という時に出てくるものです。
詳しく知りたい方はこちらがおすすめです。 [デザインパターン「Singleton」](https://qiita.com/shoheiyokoyama/items/c16fd547a77773c0ccc1)


Kotlin で実装したい時は `object` を使うだけでいいのです。

```kotlin
object Singleton
```

## 2. `@JvmStatic` について
object に 何かしらの関数があったとしましょう。

```kotlin
object Singleton {
    fun nannka(){

    }
}
```

Kotlin であれば、`Singleton.nannka()` とアクセスすることができますが
Java から実行するときは `Singleton.INSTANCE.nannka()` としなければいけません。
`nannka()` というのはシングルトン内の関数であって、staticな関数ではありません。
その為、シングルトンのインスタンスを経由してアクセスする必要があります。
しかし、`static fun` というものはありません。
その時に登場するのが、`@JvmStatic` です。
staticにしたい関数にアノテーションをつけると、static関数になります。

```kotlin
object Singleton {
    @JvmStatic
    fun nannka(){

    }
}
```
static関数になれば、Javaでも `Singleton.nannka()` のようにアクセスすることができるようになります。

どうでもいい話なので読み飛ばしてもらって構いません。
`Singleton.INSTANCE.nannka()` とアクセスできるということは、
`INSTANCE` という変数が `@JvmStatic` で定義されているということになります。
以下のような感じになっているわけですね。(`@JvmField` の方が近いです。)

```kotlin
object Singleton {
    @JvmStatic
    val INSTANCE = this
    
    fun nannka(){

    }
}
```
ちなみに、これを実行しようとすると、例外が発生します

```
java.lang.ClassFormatError: Duplicate field name "INSTANCE" with signature "LSingleton;" in class file Singleton
```

## 3. 実行時間
`@JvmStatic` をつけるかつけないかでどれだけ実行時間に違いがあるのかを検証してみます。

### 検証１

10億回関数を実行します。関数内の処理は変数の加算処理1回だけです。

#### ソースコード
```kotlin
fun main(){
    val loop = 1000000000L
    val timeJvmStatic = block(loop) {
        CounterJvmStatic.count()
    }
    val timeSingleton = block(loop) {
        CounterSingleton.count()
    }
    println("%,d:   %,d   %,d".format(loop, timeJvmStatic, timeSingleton))
}

fun block(loop: Long, run: () -> Unit): Long {
    val begin = System.currentTimeMillis()
    for(i in 0 until loop) {
        run.invoke()
    }
    val end = System.currentTimeMillis()
    return end - begin
}

object CounterJvmStatic {
    var count = 0
    
    @JvmStatic
    fun count() {
        count ++
    }
}

object CounterSingleton {
    var count = 0
    
    fun count() {
        count ++
    }
}
```
**[実際に実行する](https://pl.kotl.in/12E6FKTts)**

#### 結果
```
1,000,000,000:   665   1,736
1,000,000,000:   651   1,717
1,000,000,000:   652   1,722
```

2倍くらい違いますね。しかし、10億回実行してこの数字なわけですから、ほとんど無視できるくらいでしょうか。

### 検証２

関数内の処理が重かった場合を考えてみましょう。
10万回関数を実行します。関数内の処理は変数の加算処理を1000回です。

#### ソースコード

```kotlin
fun main(){
    val loop = 1000000L
    val timeJvmStatic = block(loop) {
        CounterJvmStatic.count()
    }
    val timeSingleton = block(loop) {
        CounterSingleton.count()
    }
    println("%,d:   %,d   %,d".format(loop, timeJvmStatic, timeSingleton))
}

fun block(loop: Long, run: () -> Unit): Long {
    val begin = System.currentTimeMillis()
    for(i in 0 until loop) {
        run.invoke()
    }
    val end = System.currentTimeMillis()
    return end - begin
}

object CounterJvmStatic {
    var count = 0
    
    @JvmStatic
    fun count() {
        for(i in 0 until 1000) count ++
    }
}

object CounterSingleton {
    var count = 0
    
    fun count() {
        for(i in 0 until 1000) count ++
    }
}
```

**[実際に実行する](https://pl.kotl.in/ty0I01sw_)**

#### 結果

```
1,000,000:   65   80
1,000,000:   55   57
1,000,000:   59   61
```

やはり、ほとんど変わりませんね。

## 4. まとめ
実行時間のためだけに `@JvmStatic` をつけるべきではないと思います。
Javaとの互換性のためのアノテーションなわけですから、Kotlinのみの開発で使うことはないでしょう。
実行時間が気になるほど、object にアクセスをするような状況なのであれば、一度変数で保持をする方が一般的だと思います。

```kotlin
object Singleton {
    fun nannka(){

    }
}

fun main(){
    val singeleton = Singleton
    singeleton.nannka()
}
```

しかし、ここで実行時間を気にするくらいであれば、他の部分で気にするべきなのでしょう。

余談ですが、object でクラスが定義されていれば、プログラムを読んでいる人からすると
「そのクラスはマルチプルである必要がない」と分かるので、理解しやすくなると思います。
積極的に object は使うべきではないでしょうか。私はそう思います。