@IntDefについて

## 経緯
私はEnumクラスが大好きなのですが、この前初めてIntDefを触りました。
独自アノテーションに対して付与する・・・？
便利そうなので調べてみました。

## IntDef（StringDef）とは
端的に言うと、Androidにおいて**Enumより軽く、型安全に定数を使用できるようになるアノテーション**のことです。

Enumを使用した場合、1つのEunmにつき1.0～1.4 KB ほど増えることがあるそうです。
サイズの増加は可能な限り避けたいので、かなり有用な方法に思えます。（[参考](https://developer.android.com/topic/performance/reduce-apk-size#remove-enums)）

## 使ってみる
とりあえずEnumのサンプルを。細かい部分は目を瞑ってください。

``` Sample.java
    public enum DayOfTheWeek {
        SUNDAY,        
        MONDAY,
        TUESDAY,
        WEDNESDAY,
        THURSDAY,
        FRIDAY,
        SATURDAY
    }
    
    public String getJPNName(DayOfTheWeek dayOfTheWeek){
        // 和名を返す
    }
```

Enumを使わないとしたら、定数で定義していく感じですかね。

``` Sample.java
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;

    public String getJPNName(int dayOfTheWeek){
        // 和名を返す
    }
```
この場合はgetJPNNameメソッドがintを受けるので、意図しない値が渡ってくるかもしれません。

そこでIntDefの出番です。
（見やすさを優先し＠Retentionは付与していませんが、公式にもついているので付与した方が良いと思います。アノテーションの読み込みタイミングを指定できるものだそうです。[参考](https://developer.android.com/reference/androidx/annotation/IntDef)）

``` Sample.java
    @IntDef({SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY})
    public @interface DayOfTheWeek {
    }

    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;

    public String getJPNName(@DayOfTheWeek int dayOfTheWeek) {
        // 和名を返す
    }
```
上記のように書くと利用する際に警告を出してくれます。
![スクリーンショット 2021-10-18 11.32.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773816/a0862fab-4265-a63a-2c5e-2c8c2d4e210a.png)

また、てきとうな値を入れると候補を出してくれます。
![スクリーンショット 2021-10-18 11.32.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773816/95be92a2-bae0-9993-6466-3851899eef51.png)


非常に便利です。ただし、ビルドは通ってしまうのでそこだけ注意ですね。

ちなみにLongDef、StringDefというものもあります。

### kotlinの場合
先ほどはJavaで定義しkotlinから呼び出しました。
なぜkotlinで定義しなかったかというと、IntDefアノテーションによるチェックがうまく働いてくれないためです。

``` Sample2.kt
    companion object {
        const val SUNDAY = 0
        const val MONDAY = 1
        const val TUESDAY = 2
        const val WEDNESDAY = 3
        const val THURSDAY = 4
        const val FRIDAY = 5
        const val SATURDAY = 6
    }

    @IntDef(SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY)
    annotation class DayOfTheWeek

    fun getJPNName(@DayOfTheWeek dayOfTheWeek: Int): String {
        // 和名にして返す
    }
```

先ほどと同じ方法で利用してみます。

![スクリーンショット 2021-10-18 11.33.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773816/1e778f1a-660f-117a-3b89-acbd7d214298.png)

![スクリーンショット 2021-10-18 11.34.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1773816/3653c31e-922b-5298-2904-6939740a0ff1.png)
なにも出ていません。

これでは逆に不便ですね。
一応コードを読めばどういう値を求めているのかはわかりますが、型安全ではないです。
現状Enumを使うしかないのかもしれません。強固に検査するのも手でしょうか・・・。

## 終わりに
IntDef自体は随分前からあったのに最近知ったのがショックでした。
勉強不足露呈ですね。
私は現在メイン言語がkotlinなので、知ったとてうまく動かないことも残念です。
なにか良い方法がないか模索していこうと思います。