概要

Properties ファイルは、DB 接続先、タイムアウト値、機能フラグなど、アプリケーションの設定を外出しする標準的な手段です。Java 標準の Properties クラスで読み書きできますが、文字コードの扱いに落とし穴があります。Properties.load(InputStream) は ISO-8859-1 でしか読めないため、日本語を含む設定ファイルでは InputStreamReader で UTF-8 を明示する必要があります。この記事では、クラスパスからの読み込み、ファイルパスからの読み込み、デフォルト値付きの安全な取得、数値変換を整理し、実務でそのまま使えるユーティリティメソッドを提供します。

使いどころ

アプリケーションの DB 接続先やタイムアウト値を application.properties に外出しして環境ごとに切り替える

バッチ処理の実行パラメータ(対象日、リトライ回数など)を設定ファイルで管理する

テスト環境と本番環境で異なるフラグ値をプロパティファイルで制御する

コード例

Properties ファイルの読み込みと安全な値取得
import java.io.FileNotFoundException;

public class PropertiesConfig {

    /** クラスパスからプロパティファイルを読み込む */
    public static Properties loadFromClasspath(String resourceName) throws IOException {
        InputStream is = PropertiesConfig.class.getClassLoader()
                .getResourceAsStream(resourceName);
        if (is == null) {
            throw new FileNotFoundException("リソースが見つかりません: " + resourceName);
        }
        var props = new Properties();
        try (var reader = new java.io.InputStreamReader(is, StandardCharsets.UTF_8)) {
            props.load(reader);
        }
        return props;
    }

    /** ファイルパスからプロパティファイルを読み込む */
    public static Properties loadFromFile(Path path) throws IOException {
        var props = new Properties();
        try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
            props.load(reader);
        }
        return props;
    }

    /** デフォルト値付きで安全に取得 */
    public static String get(Properties props, String key, String defaultValue) {
        return props.getProperty(key, defaultValue);
    }

    /** 数値として取得(変換失敗時はデフォルト値) */
    public static int getInt(Properties props, String key, int defaultValue) {
        var value = props.getProperty(key);
        if (value == null) return defaultValue;
        try {
            return Integer.parseInt(value.trim());
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public static void main(String[] args) {
        var props = new Properties();
        props.setProperty("db.url", "jdbc:postgresql://localhost:5432/mydb");
        props.setProperty("app.name", "業務アプリ");
        props.setProperty("timeout.seconds", "30");

        System.out.println(get(props, "db.url", ""));
        System.out.println(get(props, "max.retry", "3"));
        System.out.println(getInt(props, "timeout.seconds", 60));
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

var で記述が簡潔になる。Files.newBufferedReader() のデフォルトが UTF-8 のため文字コード指定を省略できる(Java 11+)。

Java 17
// Java 17: var + Files.newBufferedReader()
var props = new Properties();
try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    props.load(reader);
}
var value = props.getProperty("db.url", "jdbc:h2:mem:");

Library Comparison

Pure Java(Properties)フラットな key=value 形式で十分な場合。標準 API のみで完結したいとき。ネスト構造やリストは表現できない。プロファイル切替などの高度な機能はない。
YAML(SnakeYAML)ネスト構造やリストを含む設定が必要な場合。Spring Boot の application.yml を直接扱いたいとき。外部ライブラリの依存が増える。フラットな設定なら Properties で十分。
Typesafe Config(HOCON)環境変数の参照、include、型付きの値取得が欲しい場合。ライブラリ依存が増える。学習コストもある。

注意点

Properties.load(InputStream) は ISO-8859-1 で読み込むため、日本語値が文字化けする。必ず InputStreamReader + UTF-8 でラップすること。

getProperty() は存在しないキーで null を返す。NullPointerException を避けるため、デフォルト値付きの getProperty(key, default) を使うこと。

数値プロパティを Integer.parseInt() で変換する際、値が空文字や不正文字列の場合に NumberFormatException が発生する。try-catch でデフォルト値に戻す処理を入れること。

FAQ

Properties ファイルに日本語を書いてもよいですか。

InputStreamReader で UTF-8 を明示すれば問題ありません。native2ascii は Java 9 以降では不要です。

プロパティの順序は保持されますか。

Properties は内部的に Hashtable を継承しているため順序は保証されません。順序が必要なら LinkedHashMap に詰め替えてください。

環境変数とプロパティファイルを併用するにはどうしますか。

System.getenv() で環境変数を取得し、存在しなければプロパティファイルの値にフォールバックするパターンが一般的です。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます