2020-06-12

プログラマが絶対守るべきこと(連載第2回目:リテラルは定数にせよ)

投稿者: KuRo
今回はリテラルの扱い方について書いていこうと思います。
リテラルは初学者から扱うことが極めて多いものです。
教科書の Hello World でいきなり使います。
ですが、こいつの扱いがザツなことが多いですね。

この記事で紹介していること

リテラルは出現回数が1回でも定数にせよ

リテラルとは次の赤文字のことを言います。

悪い例

/** データベースから name のスリーサイズをmapで返却 */
public static Map<String, Integer> getThreeSize(String name){
    ThreeSizeDto threeSizeDto = threeSizeDb.getThreeSize(name);
    Map<String, Integer> retValue = new HashMap<>();
    retValue.put(“bust”, threeSizeDto.getBust());
    retValue.put(“west”, threeSizeDto.getWest());
    retValue.put(“hip”, threeSizeDto.getHip());
    return retValue;
}

/** スリーサイズのmapを生成 */
public static Map<String, Integer> setThreeSize(Integer bust, Integer west, Integer hip){
    Map<String, Integer> retValue = new HashMap<>();
    retValue.put(“bust”, bust);
    retValue.put(“west”, threeSizeDto.getWest());
    retValue.put(“hip”, threeSizeDto.getHip());
    return retValue;
}

public static void main(String[] args){
    Map<String, Integer> threeSizeMap = getThreeSize(args[0]);
    System.out.println(args[0] + “さんのバストサイズは” + threeSizeMap.get(“bust”));
}

これセットする側も参照側も同じこと書いてますよね。
人間がプログラムを追ってみれば、“bust”とは、threeSizeDto.getBust() を表しているとわかりますが、「追わないとわからない」んですよ。
追わせないでください。時間の無駄です。
これを定数にすることで、定数から意味を知ることができます。

良い例

/** 定数 */
public class Constants {
    /** スリーサイズのバスト */
    public static final String KEY_THREE_SIZE_BUST = “bust”;
    /** スリーサイズのウエスト */
    public static final String KEY_THREE_SIZE_WEST = “west”;
    /** スリーサイズのヒップ */
    public static final String KEY_THREE_SIZE_HIP = “hip”;
}

/** データベースから name のスリーサイズをmapで返却 */
public static Map<String, Integer> getThreeSize(String name){
    ThreeSizeDto threeSizeDto = threeSizeDb.getThreeSize(name);
    Map<String, Integer> retValue = new HashMap<>();
    retValue.put(KEY_THREE_SIZE_BUST , threeSizeDto.getBust());
    retValue.put(KEY_THREE_SIZE_WEST , threeSizeDto.getWest());
    retValue.put(KEY_THREE_SIZE_HIP , threeSizeDto.getHip());
    return retValue;

}

/** スリーサイズのmapを生成 */
public static Map<String, Integer> setThreeSize(Integer bust, Integer west, Integer hip){
    Map<String, Integer> retValue = new HashMap<>();
    retValue.put(KEY_THREE_SIZE_BUST , bust);
    retValue.put(KEY_THREE_SIZE_WEST , threeSizeDto.getWest());
    retValue.put(KEY_THREE_SIZE_HIP , threeSizeDto.getHip());
    return retValue;

}

public static void main(String[] args){
    Map<String, Integer> threeSizeMap = getThreeSize(args[0]);
    System.out.println(args[0] + “さんのバストサイズは” + threeSizeMap.get(KEY_THREE_SIZE_BUST ));
}

こうすることで、リテラルの直記載では得られなかった「意味のつながり」が表現されます。
getThreeSize と setThreeSize で、定数を共有しているため、全く同じ意味の map であることが表現されます。
※Javaをちゃんとやっている人にとっては「そんなの、ちゃんと部品共通化すればいいじゃん」という声もあろうかと思いますが、それでも部品が拡張されたときのことを考えれば、すべてを定数にするほうが、将来的に良いと私は確信しています。

定数にするメリット・デメリット

メリット

  • mapキーに共通の意味のつながりを持たせることができる(ServletRequest で多用されますね)
  • 定数からIDEで使用箇所をたどることができる(マイグレーションで大活躍)
  • 変更耐性が強い(拡張時に、定数だけ変更すればよいケースが多い)

デメリット

  • コード量が多くなる(単純にめんどくさい)
メリデメだけを見ても、やって損はないと思います。

まとめ:リテラル書いたら、定数にしよう

リテラルを書く機会って、本当にたくさんあります。
現代のプログラムは、ほとんどがフレームワークで作られます。
フレームワークでは、データにキー値で意味づけすることが多く、早く作れるので、都度都度リテラルを書いてしまいがちです。
ぜひリテラルをロジック中に書くことになったら、定数にすることをおススメします。
この説明だけで、そのメリットが十分に伝わっていなくても、近くきっとあなたにとって、「やっててよかった」の瞬間があるはずです。
※次回は変数名について記載します。