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

# 0. INDEX
- 概要と目的
- enumでユーティリティを作る
- あとがき

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

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

```properties
HOGE=hoge
```

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

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

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

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

[^1]: バイオ4かな


# 2. enumでユーティリティを作る
## 2.1. 動作サンプル
[https://paiza.io/projects/QahskFkN9ltEvxJBG_7_Tw](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`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92447/504a1fa8-a3c9-bdbc-4daa-373ae5c822cb.png)

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

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

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


## 2.3. 列挙型の名前をキーそのものとして使う場合
列挙型は`toString()`でキーがそのまま文字列になる事を利用する。

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

```Java
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() + "]");
		}
	}
}
```

### 実行結果
```console
HOGE: get()=[hoge], getInt()=[-1]
FUGA: get()=[fuga], getInt()=[-1]
PIYO: get()=[123], getInt()=[123]
```

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

### ソースコード
```Java
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() + "]");
		}
	}
}
```

### 実行結果
```console
FOO: get()=[ふーふー], getInt()=[-1]
BAR: get()=[ばーばー], getInt()=[-1]
BAZ: get()=[456], getInt()=[456]
```

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

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

以上！