ApexのSwitchステートメントはいつ使えばいいのか？

# 昔の話
昔Salesforceの開発を始めたばかりのころ、割合が0 ～ 10 ％ならこれ、10 ～ 50 ％ならこれ～のような分岐を書こうとしてSwitch文が使えないことに~~面倒だなーと~~驚いたことがありました。
時は流れて[Summer'18リリースからSwitchステートメントが使用できるようになっていた](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/langCon_apex_switch.htm)ものの、リリースノート読まない勢なのでしばらく使えることに気が付いていませんでした。

# How to use
あまりに長い間使わなかったせいで、「だいたいIf-elseステートメントでも困らないよな」とか思ってましたが、最近コーディングする機会があったのでもっと使えそうな場所について考えてみようと思います。
基本構文はこんな感じ。

```java:
switch on expression {
    when value1 {		// when block 1
        // code block 1
    }	
    when value2 {		// when block 2
        // code block 2
    }
    when value3 {		// when block 3
        // code block 3
    }
    when else {		  // default block, optional
        // code block 4
    }
}
```
whenには1つの値、複数の値、sObjectを使用できるとのこと。

## 使用例
最初にSwitchステートメントを使おうかなーと思ったのは取引先ごとに各月の商談の金額を集計して、1レコードにまとめる処理を実装しようと思った時でした。
各レコードは以下のような形で集計するものとします。

|取引先  |年度 |4月  |5月  |6月  |7月  |8月  |9月  |10月  |11月  |12月  |1月  |2月  |3月  |
|:--------|:--------|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|会社A|2018|¥300|¥300|¥300|¥300|¥300|¥300|¥300|¥300|¥300|¥300|¥300|¥300|
|会社A|2017|¥200|¥200|¥200|¥200|¥200|¥200|¥200|¥200|¥200|¥200|¥200|¥200|
|会社B|2018|¥250|¥200|¥250|¥200|¥250|¥200|¥250|¥200|¥250|¥200|¥250|¥200|

1レコードの中に1～12月までのカスタム項目を作成しているので、If～elseステートメントの場合、以下のような方法で記載することになります。

```java:
Decimal january = 0;
Decimal february = 0;
Decimal march = 0;
Decimal april = 0;
Decimal may = 0;
Decimal june = 0;
Decimal july = 0;
Decimal august = 0;
Decimal september = 0;
Decimal october = 0;
Decimal nobember = 0;
Decimal december = 0;

for (Opportunity opp : opportunityList) {
    if (opp.CloseDate.month() == 1) {
        january += opp.Amount;
    } else if (opp.CloseDate.month() == 2) {
        february += opp.Amount;
    } else if (opp.CloseDate.month() == 3) {
        march += opp.Amount;
    } else if (opp.CloseDate.month() == 4) {
        april += opp.Amount;
    } else if (opp.CloseDate.month() == 5) {
        may += opp.Amount;
    } else if (opp.CloseDate.month() == 6) {
        june += opp.Amount;
    } else if (opp.CloseDate.month() == 7) {
        july += opp.Amount;
    } else if (opp.CloseDate.month() == 8) {
        august += opp.Amount;
    } else if (opp.CloseDate.month() == 9) {
        september += opp.Amount;
    } else if (opp.CloseDate.month() == 10) {
        october += opp.Amount;
    } else if (opp.CloseDate.month() == 11) {
        nobember += opp.Amount;
    } else {
        december += opp.Amount;
    }
}

```
一方でSwitchステートメントを使用すると、上記のコードは以下のように置き換えることができます。

```java:
Decimal january = 0;
Decimal february = 0;
Decimal march = 0;
Decimal april = 0;
Decimal may = 0;
Decimal june = 0;
Decimal july = 0;
Decimal august = 0;
Decimal september = 0;
Decimal october = 0;
Decimal nobember = 0;
Decimal december = 0;

for (Opportunity opp : opportunityList) {
    switch on opp.CloseDate.month() {
        when 1 { january += opp.Amount; }
        when 2 { february += opp.Amount; }
        when 3 { march += opp.Amount;}
        when 4 { april += opp.Amount; }
        when 5 { may += opp.Amount; }
        when 6 { june += opp.Amount; }
        when 7 { july += opp.Amount; }
        when 8 { august += opp.Amount; }
        when 9 { september += opp.Amount; }
        when 10 { october += opp.Amount; }
        when 11 { nobember += opp.Amount; }
        when else { december += opp.Amount; }
    }
}

```
これで可読性がだいぶ上がったような気がします。

## 他の使い道はどんなものがあるか？
whenの値をnullにすることができるとのことなので、例えば以下のように置き換えることができます。
これは結構便利そうです。

```java:
// If～elseステートメント
if (i != null) {
    if (i == 2) {
        System.debug('when block 2');
    } else {
        System.debug('default ' + i);
    }
} else {
    System.debug('bad integer');
}

// Switchステートメント
switch on i {
   when null { System.debug('bad integer'); }
   when 2 { System.debug('when block 2'); }
   when else { System.debug('default ' + i); }
}
```
また、メソッドコールの結果も利用できるので、思ったよりも利用の幅が多そうです。

```java:
// If～elseステートメント
Integer j = someInteger(i);
if (j == 2) {
    System.debug('when block 2');
} else if (j == 3) {
    System.debug('when block 3');
} else {
    System.debug('bad integer');
}

// Switchステートメント
switch on someInteger(i) {
   when 2 { System.debug('when block 2'); }
   when 3 { System.debug('when block 3'); }
   when else { System.debug('default'); }
}
```
システム上あまり意識したことがないのですが、そのうちどちらの処理の方が早いかについても調査してみようかなと思います。

# 参考
[こちら](https://qiita.com/xuwenzhen/items/38b6b642ea64b86e949a)は個人的に頭いいなーと思った使い方です。
トリガーの実装方法も含めてこんな考え方ができるようになりたいものです。