【Java】enumでpropertiesファイル読み込みユーティリティを作る


0. INDEX

  • 概要と目的
  • enumでユーティリティを作る
  • あとがき

1. 概要と目的

いつものコピペ用。
設定ファイルから値を取得する時に、使う度に文字リテラル指定にするとtypoるのでその対策。
Eclipse等のコードアシスト環境があれば多分事故る確率は減るハズ!

という事で、今回の目的はこんなプロパティファイルがある時に

HOGE=hoge

こういう風にコードアシストを使ってtypoしない様に実装したい!

String value = Config.HOGE.get();
System.out.println(value); // "hoge"と出力

だって、↓こう書いておいてtypoに気づかずに
「先輩、ここでなぜかぬるぽが出ちゃうんです…」
とか、あ゛ぅ゛ん゛!1 もうっ!ってなるじゃないですか!!1

String value = Config.get("H0GE");
if (value.length) { // ここでドーンだYO!!
    // 処理
}

2. enumでユーティリティを作る

2.1. 動作サンプル

https://paiza.io/projects/QahskFkN9ltEvxJBG_7_Tw

2.2 前提条件

JDKは、Amazon Corretto 15を使用した。
…が、新しい構文やクラスは使っていないのでJDK 8でも大丈夫だと思う。(試していない)

Mavenプロジェクトを利用し、ここでは以下の位置にプロパティファイルを設置する。
各自の環境に合わせて適宜読み替える事。

  • Eclipse上では、/src/main/resources/config.properties
  • 単独実行時は、/target/classes/config.properties

中身はこんな感じ。文字コードはUTF-8。

# 列挙型の名前をキーそのものとして使う
HOGE=hoge
FUGA=fuga
PIYO=123

# 列挙型に任意の専用キーを設定して使う
foo.foo=ふーふー
bar.bar=ばーばー
baz.baz=456

2.3. 列挙型の名前をキーそのものとして使う場合

列挙型はtoString()でキーがそのまま文字列になる事を利用する。

ソースコード全体

propertiesファイルの読み込み方は色々派生があるのでお好みで。このサンプルだと読み込み失敗時は音信不通だし。

package jp.co.neosystem.neonemo.qiita.conf;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Properties;

/**
 * 列挙型そのものをキーとして拾う
 * @author neonemo
 */
public enum Config1 {
    HOGE,
    FUGA,
    PIYO,
    ;

    private static Properties prop;
    static {
        prop = new Properties();
        try (Reader reader = new InputStreamReader(Config1.class.getResourceAsStream("/config.properties"), "UTF-8")) {
            prop.load(reader);
        } catch (IOException e) {
            // 設定ファイルが無いか、文字コードが変という実行時エラーと解釈するので!
            throw new RuntimeException(e);
        }
    }

    public String get() {
        return prop.getProperty(this.toString());
    }

    public int getInt() {
        String v = get();
        return (v != null) && v.matches("[0-9]+") ? Integer.parseInt(v) : -1;
    }

    /**
     * 動作確認用
     * @param args (使用しない)
     */
    public static void main(String[] args) {
        for (Config1 conf : Config1.values()) {
            System.out.println(conf.toString() + ": get()=[" + conf.get() + "], getInt()=[" + conf.getInt() + "]");
        }
    }
}

実行結果

HOGE: get()=[hoge], getInt()=[-1]
FUGA: get()=[fuga], getInt()=[-1]
PIYO: get()=[123], getInt()=[123]

2.4. 列挙型に埋め込んだ文字列をキーとして使う場合

列挙型に引数を付けた場合、コンストラクタで調整できる事を利用する。複数コンストラクタを用意すればパラメータ数自体を変えたりと自由度が上がる。任意のメソッドも持たせられるし、内部的にはクラスって事になるのかな。

ソースコード

package jp.co.neosystem.neonemo.qiita.conf;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Properties;

/**
 * 列挙型に埋め込んだ文字列をキーとして拾う
 * @author neonemo
 */
public enum Config2 {
    FOO("foo.foo"),
    BAR("bar.bar"),
    BAZ("baz.baz"),
    ;

    private static Properties prop;
    static {
        prop = new Properties();
        try (Reader reader = new InputStreamReader(Config2.class.getResourceAsStream("/config.properties"), "UTF-8")) {
            prop.load(reader);
        } catch (IOException e) {
            // 設定ファイルが無いか、文字コードが変という実行時エラーと解釈するので!
            throw new RuntimeException(e);
        }
    }

    private String key;

    private Config2(String key) {
        this.key = key;
    }

    public String get() {
        return prop.getProperty(key);
    }

    public int getInt() {
        String v = get();
        return (v != null) && v.matches("[0-9]+") ? Integer.parseInt(v) : -1;
    }

    /**
     * 動作確認用
     * @param args (使用しない)
     */
    public static void main(String[] args) {
        for (Config2 conf : Config2.values()) {
            System.out.println(conf.toString() + ": get()=[" + conf.get() + "], getInt()=[" + conf.getInt() + "]");
        }
    }
}

実行結果

FOO: get()=[ふーふー], getInt()=[-1]
BAR: get()=[ばーばー], getInt()=[-1]
BAZ: get()=[456], getInt()=[456]

3. あとがき

今回の記事は、引数に列挙型を使う方法はよくあるけど、似たような処理をさせる場合に使い方を間違わせない。直感的に使わせたい。そんな時に良いかなと思う。
また、設定ファイルの読み込み以外にも、Factoryを作ったり、何らかのアルゴリズム名を指定するようなハッシュ生成ユーティリティなんかも出来る。

まあ、これは次の記事のネタにしようと思います。

以上!


  1. バイオ4かな