読み込み中...

Javaでプロパティファイルを読み込むたった7つの方法

Javaプロパティファイル使用方法の解説イメージ Java
この記事は約37分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaでプロパティファイルを扱う結論は、java.util.Propertiesで小さな設定を分離し、文字コードと配置場所を明示して読み書きすることです。初心者がつまずきやすいのは、load(InputStream)load(Reader)の文字コード差、クラスパスから読み込む場合のパス指定、存在しないキーを読んだときのnull処理になります。

そのため、プロパティファイルの使い方は「キーと値の形式」「読み込む経路」「書き込む方法」「エンコーディング」「カスタマイズ」の順に整理すると理解しやすくなります。設定をソースコードから外へ出すと、環境ごとの差分をファイル側に集められ、Javaアプリケーションの修正範囲を小さくできるのが基本です。

動作確認環境
  • Java 21 LTS / OpenJDK 21
  • 標準ライブラリ: java.util.Propertiesjava.util.ResourceBundle
  • コマンド実行例: javacjava
📖 この記事で学べること
  • プロパティファイルの基本構造とコメントの書き方
  • Propertiesで設定を読み込む実装パターン
  • プロパティファイルへ値を書き込むサンプルコード
  • UTF-8とISO-8859-1の扱い方の違い
  • 多言語対応、継承、カスタマイズの考え方

Javaとプロパティファイルについて

Javaは、JVM上で動くアプリケーションを作るための言語で、Webシステム、バッチ処理、業務アプリケーションなどで使われます。設定値をコードへ直接書くと、環境を変えるたびに再ビルドや再デプロイが必要になりやすいため、外部ファイルへ切り出す設計がよく採用されます。

その外部ファイルとして扱いやすい形式が、拡張子.propertiesのプロパティファイルです。Java標準のPropertiesクラスは、キーと値の組み合わせを読み込む、更新する、保存するという処理をまとめて扱えますし、ここがポイントです。公式ドキュメントによれば、Properties APIは永続的なプロパティ集合を表すクラスです。

これにより、データベース接続先、ログ出力レベル、外部APIのURL、画面表示メッセージなどをJavaコードから分離できます。初心者は、値を外部化する対象とソースコードへ残す対象を混同しがちですが、変更頻度が高い設定ほどプロパティファイルへ寄せると管理しやすくなります。

ただし、パスワードやAPIキーなどの機密情報を平文で置くと、リポジトリ流出やサーバー内の閲覧権限によるリスクが残りますが、これは押さえたい点です。そのため、プロパティファイルは設定の分離に向いていても、秘密情報の保管先としては権限管理や環境変数、シークレット管理サービスとの使い分けが必要になります。

関連するJavaの基礎を固める場合は、コレクションの扱いを整理したJava List型完全ガイドも合わせて確認できます。アノテーションによる設定注入やフレームワーク連携を理解したい場合は、Javaアノテーションの解説が補助になるのが目安です。

項目主な役割関連するAPI注意点
.propertiesキーと値を保存Properties小規模な設定向け
key=value基本の記法getPropertyキー名の重複に注意
#コメント行load行頭で使う
!コメント行load設定値内ではエスケープを検討
FileReader文字ストリームload(Reader)文字コードを意識する
FileInputStreamバイトストリームload(InputStream)ISO-8859-1扱いに注意
FileWriter文字として保存store(Writer)出力文字コードを確認
FileOutputStreamバイトとして保存store(OutputStream)日本語はエスケープされる場合がある
InputStreamReader文字コード変換StandardCharsets.UTF_8読み書きで同じ文字コードにする
OutputStreamWriter文字コード付き出力storeUTF-8保存に使う
ResourceBundle多言語対応getBundleファイル名規則がある
Locale言語や地域Locale.ENGLISHフォールバックを考える
getResourceAsStreamクラスパス読み込みClassnull確認が必要
setProperty値を設定Properties値は文字列
storeファイルへ保存Propertiesコメントや日時が入る場合がある
IOException入出力例外try-catch握りつぶさない
try-with-resources自動クローズAutoCloseable入出力処理で使う
null値なしgetPropertyデフォルト値を検討
UTF-8日本語を扱う文字コードReader明示指定が安全
ISO-8859-1バイト系loadの前提InputStream日本語は注意
uXXXXUnicodeエスケープnative2ascii可読性が下がる
db.url階層風キーgetProperty命名規則を統一
config.properties設定ファイル名FileInputStream配置場所を固定
messages_ja.properties日本語リソースResourceBundleベース名と対応させる
messages_en.properties英語リソースResourceBundleロケール名をそろえる
containsKeyキー確認Hashtable欠落時の分岐に使う
stringPropertyNamesキー一覧取得Set検査やログに使う
defaults親設定Properties(Properties)上書き順を決める
System.getenv環境変数System秘密情報で併用しやすい
Pathファイルパスjava.nio.file相対パスに注意

プロパティファイルの基本構造

プロパティファイルは、1行に1組のキーと値を書く単純な形式です。キーと値の区切りには=:を使えますが、チーム内で表記をそろえるならkey=valueに統一するほうが読みやすくなります。

この形式では、db_hostdb_userのようなキーが設定項目名になり、右側の値がJavaプログラムから取り出されます。ただし、同じキーを複数行に書いた場合は後から読み込まれた値で上書きされるため、重複を避ける運用が必要です。

# データベースの設定
db_host=localhost
db_user=root
db_password=secret

結果: 期待される内容は、db_hostdb_userdb_passwordの各キーが値と対応して保存された状態です。

そのファイルをJavaから読み込むときは、Propertiesのインスタンスを作り、loadで内容を取り込みますし、これが一つの目安です。取り込んだ後はgetPropertyで文字列として値を取得できるため、初心者でも流れを追いやすいサンプルコードになります。

import java.util.Properties;
import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        Properties properties = new Properties();

        // プロパティファイルを読み込む
        try (FileReader reader = new FileReader("config.properties")) {
            properties.load(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 値を取得する
        String dbHost = properties.getProperty("db_host");
        String dbUser = properties.getProperty("db_user");
        String dbPassword = properties.getProperty("db_password");

        // 結果を出力
        System.out.println("DB Host: " + dbHost);
        System.out.println("DB User: " + dbUser);
        System.out.println("DB Password: " + dbPassword);
    }
}

結果: 期待される出力は、ファイル内の設定に対応してDB Host: localhostなどがコンソールへ並ぶ形です。

このとき、config.propertiesが実行時のカレントディレクトリにない場合、FileNotFoundExceptionが発生します。設定ファイルを外部に置く運用では、起動スクリプトの作業ディレクトリや絶対パスの扱いまで決めておくと混乱を減らせます。

DB Host: localhost
DB User: root
DB Password: secret

結果: 期待される出力例は、プロパティファイルから読み込んだ3件の設定値が行ごとに表示される形式です。

コメントを書く場合は、行頭に#または!を置きますが、覚えておくと役立つでしょう。コメントは設定値として扱われないため、なぜその値なのか、どの環境で使うのかを残す用途に向いています。

# これはコメントです
! これもコメントです

# データベースの設定
db_host=localhost

結果: 期待される解釈は、コメント行が読み飛ばされ、db_host=localhostだけがプロパティとして扱われる状態です。

プロパティファイルの読み込み

プロパティファイルを読み込む方法は、ファイルシステムから読む方法と、クラスパスから読む方法に分けられます。小さな学習用プログラムではFileReaderFileInputStreamを使えますが、WebアプリケーションではgetResourceAsStreamでリソースとして読み込む設計もよく使われますし、ここを基本と考えるとよいでしょう。

そのため、単に読み込むだけでなく、配置場所、文字コード、例外処理、デフォルト値を合わせて設計する必要があります。Javaエスケープ処理の解説を確認しておくと、特殊文字を含む設定値の扱いも整理しやすくなります。

サンプルコード1:Propertiesクラスを使って読み込む

基本的な読み込みでは、PropertiesFileReadertry-with-resourcesを組み合わせますし、ここがポイントです。try-with-resourcesにより、読み込み後のreaderは自動的に閉じられます。

import java.util.Properties;
import java.io.FileReader;
import java.io.IOException;

public class ReadProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        // プロパティファイルの読み込み
        try (FileReader reader = new FileReader("settings.properties")) {
            properties.load(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // プロパティの使用
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");

        System.out.println("Username: " + username);
        System.out.println("Password: " + password);
    }
}

結果: 期待される出力は、settings.propertiesにあるusernamepasswordの値がコンソールへ表示される形です。

このサンプルコードでは、loadReaderを渡しているため、文字としてファイルを扱います。ただし、FileReaderは実行環境のデフォルト文字コードに依存するため、文字コードを固定したい場合は後のUTF-8例のようにInputStreamReaderを使います。

username=admin
password=1234

結果: 期待される出力は、Username: adminPassword: 1234の2行です。

サンプルコード2:FileInputStreamを使って読み込む

一方、FileInputStreamはバイトストリームとしてファイルを開きますが、これは押さえたい点です。公式ドキュメントによれば、load(InputStream)はISO-8859-1として扱われるため、日本語を含むプロパティファイルでは文字化けやエスケープ表記に注意します。

import java.util.Properties;
import java.io.FileInputStream;
import java.io.IOException;

public class ReadPropertiesWithStream {
    public static void main(String[] args) {
        Properties properties = new Properties();

        // プロパティファイルの読み込み
        try (FileInputStream stream = new FileInputStream("settings.properties")) {
            properties.load(stream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // プロパティの使用
        String host = properties.getProperty("host");
        String port = properties.getProperty("port");

        System.out.println("Host: " + host);
        System.out.println("Port: " + port);
    }
}

結果: 期待される出力は、hostportの値を読み取り、Host: localhostのように表示する形式です。

この書き方は、英数字だけの設定を扱う場合には短く済みます。日本語のメッセージや全角記号を入れる予定がある場合は、InputStreamReaderStandardCharsets.UTF_8を組み合わせた読み込みのほうが扱いやすくなります。

host=localhost
port=8080

結果: 期待される出力は、Host: localhostPort: 8080の2行です。

💡 Tips: ファイルが見つからない問題は、Javaの文法より実行ディレクトリの差で起きることがあるのがポイントです。相対パスを使う場合は、起動コマンドを実行する場所とsettings.propertiesの位置を合わせます。

プロパティファイルの書き込み

プロパティファイルは読み込むだけでなく、アプリケーション側から書き込むこともできます。ユーザー設定や初期化済みのテンプレートを保存する場合、setPropertyで値を入れ、storeでファイルへ出力するのが一般的です。

ただし、アプリケーションの本番設定を実行中に上書きする設計では、競合や誤更新が起きる可能性があります。そのため、書き込み用途では保存先の権限、バックアップ、同時実行時の扱いをあらかじめ決めます。

サンプルコード3:Propertiesクラスを使って書き込む

文字ストリームとして保存する場合は、FileWriterstore(Writer, String)を使えるのが現実的です。コメント文字列を渡すと、保存されたファイルの先頭付近にコメントとして出力されます。

import java.util.Properties;
import java.io.FileWriter;
import java.io.IOException;

public class WriteProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        // プロパティに値を設定
        properties.setProperty("username", "admin");
        properties.setProperty("password", "1234");

        // プロパティファイルへの書き込み
        try (FileWriter writer = new FileWriter("settings.properties")) {
            properties.store(writer, "User Settings");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

結果: 期待される内容は、settings.propertiesusernamepasswordが保存される形です。

このサンプルコードで生成されるファイルには、コメントや保存日時が入る場合があります。バージョン管理したい設定ファイルでは、ツールが自動出力する差分が増えないよう、生成ファイルと手書きファイルを分ける設計も考えられます。

#User Settings
username=admin
password=1234

結果: 期待される保存内容は、コメント行に続いてusername=adminpassword=1234が並ぶ形式です。

サンプルコード4:FileOutputStreamを使って書き込む

FileOutputStreamを使うと、バイトストリームとしてプロパティファイルを書き出せます。英数字中心のサーバー設定であれば短く書けますが、日本語を多く含む場合はUTF-8の書き込み例と比較して選びます。

import java.util.Properties;
import java.io.FileOutputStream;
import java.io.IOException;

public class WritePropertiesWithStream {
    public static void main(String[] args) {
        Properties properties = new Properties();

        // プロパティに値を設定
        properties.setProperty("host", "localhost");
        properties.setProperty("port", "8080");

        // プロパティファイルへの書き込み
        try (FileOutputStream stream = new FileOutputStream("server_settings.properties")) {
            properties.store(stream, "Server Settings");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

結果: 期待される内容は、server_settings.propertieshostportが保存される形です。

その保存先をアプリケーションの起動時に読み込むと、ポート番号やホスト名をファイル側で差し替えられます。Javaの条件分岐やオーバーライドの考え方も絡むため、関連する基礎としてJavaのオーバーライド解説も参考になります。

#Server Settings
host=localhost
port=8080

結果: 期待される保存内容は、host=localhostport=8080が含まれるサーバー設定ファイルです。

プロパティファイルでのエンコーディング

プロパティファイルで日本語を扱う場合、エンコーディングの理解が欠かせません。特にJavaのPropertiesは、InputStream系とReader系で文字の扱いが変わるため、読み込む処理と書き込む処理の組み合わせを固定します。

公式ドキュメントによれば、load(Reader)store(Writer, String)は文字ストリームを扱い、load(InputStream)store(OutputStream, String)はISO-8859-1を前提に動作します。この違いを知らないままカスタマイズすると、設定値の一部だけが文字化けする原因になると整理できます。

UTF-8での読み書き

UTF-8で扱いたい場合は、InputStreamReaderOutputStreamWriterで文字コードを明示します。現在のJavaではStandardCharsets.UTF_8を使うと、文字コード名のタイプミスも避けやすくなります。

import java.io.*;
import java.util.Properties;

public class PropertiesUTF8Example {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        // プロパティに値を設定(UTF-8で日本語も設定可能)
        properties.setProperty("言語", "日本語");
        properties.setProperty("message", "こんにちは");

        // UTF-8で書き込み
        try (OutputStreamWriter writer = new OutputStreamWriter(
                 new FileOutputStream("utf8_properties.properties"), "UTF-8")) {
            properties.store(writer, "UTF-8 Settings");
        }

        // UTF-8で読み込み
        Properties loadedProperties = new Properties();
        try (InputStreamReader reader = new InputStreamReader(
                 new FileInputStream("utf8_properties.properties"), "UTF-8")) {
            loadedProperties.load(reader);
        }

        System.out.println(loadedProperties.getProperty("言語"));  // 出力: 日本語
        System.out.println(loadedProperties.getProperty("message"));  // 出力: こんにちは
    }
}

結果: 期待される出力は、日本語こんにちはが1行ずつ表示される形です。

この方法では、書き込みと読み込みの両方でUTF-8を使っています。片方だけをUTF-8にすると、保存された文字列と読み出すときの解釈がずれ、初心者には原因を追いにくい不具合になります。

ISO-8859-1での読み書き

一方、英数字中心の設定であれば、FileInputStreamFileOutputStreamによる標準的な読み書きも選択できると理解できます。ISO-8859-1の範囲に収まる値だけなら、短いコードで構成できます。

import java.util.Properties;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class PropertiesISOExample {
    public static void main(String[] args) {
        Properties properties = new Properties();

        // プロパティに値を設定(ISO-8859-1の範囲内の文字を使用)
        properties.setProperty("language", "English");
        properties.setProperty("message", "Hello");

        // 書き込み
        try (FileOutputStream stream = new FileOutputStream("iso_properties.properties")) {
            properties.store(stream, "ISO-8859-1 Settings");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 読み込み
        Properties loadedProperties = new Properties();
        try (FileInputStream stream = new FileInputStream("iso_properties.properties")) {
            loadedProperties.load(stream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println(loadedProperties.getProperty("language"));  // 出力: English
        System.out.println(loadedProperties.getProperty("message"));  // 出力: Hello
    }
}

結果: 期待される出力は、EnglishHelloが1行ずつ表示される形式です。

⚠️ 注意: 日本語を含むプロパティファイルをload(InputStream)で読み込む場合、文字コードの扱いを確認します。日本語メッセージの設定には、UTF-8を明示する読み込みのほうが意図を保ちやすくなります。

プロパティファイルの応用例

プロパティファイルは、単純な設定だけでなく、多言語対応やデータベース接続設定の一括管理にも使えると覚えるとよいでしょう。Java標準のResourceBundleを使うと、ロケールごとに異なる文言ファイルを読み込む構成を作れます。

公式ドキュメントによれば、ResourceBundle APIはロケール固有のオブジェクトを扱う仕組みです。プロパティファイルを文言管理に使う場合、messages_ja.propertiesmessages_en.propertiesのように命名規則をそろえます。

サンプルコード5:多言語対応

多言語対応では、同じキーに対して言語ごとの値を用意すると考えられます。画面やログに出す文言をJavaコードへ直接書かず、リソースファイルへ寄せることで、翻訳や表記変更の影響範囲を小さくできます。

import java.util.Locale;
import java.util.ResourceBundle;

public class MultilanguageExample {
    public static void main(String[] args) {
        // 英語のロケール設定
        ResourceBundle enBundle = ResourceBundle.getBundle("messages", Locale.ENGLISH);
        System.out.println(enBundle.getString("greeting"));

        // 日本語のロケール設定
        ResourceBundle jaBundle = ResourceBundle.getBundle("messages", Locale.JAPANESE);
        System.out.println(jaBundle.getString("greeting"));
    }
}

結果: 期待される出力は、英語用ファイルのgreetingと日本語用ファイルのgreetingが順に表示される形です。

この使い方では、messages_en.propertiesmessages_ja.propertiesをクラスパス上に置く必要があります。ファイル名、ベース名、Localeの対応がずれると、意図した言語のプロパティファイルを読み込むことができません。

サンプルコード6:設定値の一括管理

データベース設定は、プロパティファイルの代表的な用途です。URL、ユーザー名、接続オプションをまとめると、環境ごとの差し替えがファイル単位で扱えます。

import java.util.Properties;
import java.io.InputStream;

public class DatabaseConfigExample {
    public static void main(String[] args) {
        Properties properties = new Properties();
        try (InputStream stream = DatabaseConfigExample.class.getResourceAsStream("/database.properties")) {
            properties.load(stream);
        } catch (Exception e) {
            e.printStackTrace();
        }

        String url = properties.getProperty("db.url");
        String username = properties.getProperty("db.username");
        String password = properties.getProperty("db.password");

        System.out.println("URL: " + url);
        System.out.println("Username: " + username);
        System.out.println("Password: " + password);
    }
}

結果: 期待される出力は、database.propertiesにあるdb.urldb.usernamedb.passwordの値が表示される形です。

ただし、getResourceAsStreamは対象ファイルが見つからないとnullを返します。一般的には、Objects.requireNonNullで早めに検出するか、ファイルがない場合のエラーメッセージを明確にします。

サンプルコード7:ネストされたプロパティ

プロパティファイル自体にJSONのような階層構造はありませんが、キー名に.を含めることで階層風に見せられますし、これが一つの目安です。user.phone.mobileのような命名は、関連する設定をまとめて読む助けになります。

import java.util.Properties;

public class NestedPropertiesExample {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty("user.name", "Alice");
        properties.setProperty("user.email", "alice@example.com");
        properties.setProperty("user.phone.mobile", "090-1234-5678");
        properties.setProperty("user.phone.home", "03-1234-5678");

        String mobilePhone = properties.getProperty("user.phone.mobile");
        System.out.println("Mobile Phone: " + mobilePhone);
    }
}

結果: 期待される出力は、Mobile Phone: 090-1234-5678です。

この設計はシンプルな設定には向きますが、配列や深い入れ子を扱う場合はJSON、YAML、データベースなど別形式を検討します。Javaで日付や条件判定も扱う場合は、設定から値を読み込んだ後の分岐例としてJavaでうるう年を判定する解説も確認できます。

注意点と対処法

プロパティファイルの注意点は、文字、量、秘密情報、パス、例外処理に集まりますが、覚えておくと役立つでしょう。初心者は「ファイルに分けたから安全」と考えがちですが、ファイル化は管理を分離するだけであり、アクセス制御や暗号化の代わりにはなりません。

そのため、読み込む値の検証、存在しないキーの扱い、デフォルト値の決め方を設計に含めます。getProperty(key, defaultValue)を使えば、キーが存在しない場合の値を明示でき、NumberFormatExceptionなどの後続エラーも抑えやすくなります。

特殊文字の扱い

特殊文字を扱う場合は、UnicodeエスケープやUTF-8読み込みを選びますし、ここを基本と考えるとよいでしょう。古い運用ではu3053のようなUnicodeエスケープが使われることがありますが、人が直接読むファイルでは可読性が下がります。

import java.io.FileOutputStream;
import java.util.Properties;

public class SpecialCharacterHandling {
    public static void main(String[] args) {
        Properties prop = new Properties();

        // Unicodeエスケープを用いて特殊文字を設定
        prop.setProperty("message", "u3053u3093u306Bu3061u306F");  // こんにちは in Unicode

        try (FileOutputStream output = new FileOutputStream("config.properties")) {
            prop.store(output, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

結果: 期待される保存内容は、messageキーにUnicodeエスケープ形式の文字列が入ったconfig.propertiesです。

この例では、プロパティファイルへ文字列を保存しています。読み込む側で同じ形式を想定していれば利用できますが、新規のJavaアプリケーションではUTF-8を明示したReader系APIを使うほうが読みやすい構成になります。

大量のデータを扱う際の注意点

プロパティファイルは小規模な設定に向く形式です。大量データを保存すると、読み込み時間、差分確認、レビュー、検索性の面で扱いにくくなるため、アプリケーションデータの保存先として使うのは避けますし、ここがポイントです。

import java.io.FileOutputStream;
import java.util.Properties;

public class LargeDataHandling {
    public static void main(String[] args) {
        Properties prop = new Properties();

        // 大量のデータを追加
        for (int i = 0; i < 10000; i++) {
            prop.setProperty("key" + i, "value" + i);
        }

        try (FileOutputStream output = new FileOutputStream("large_config.properties")) {
            prop.store(output, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

結果: 期待される内容は、large_config.propertieskey0=value0からkey9999=value9999までのような多数の行が保存される形です。

ただし、このような量になると、設定ファイルというよりデータファイルに近くなります。検索、更新、整合性が必要な値は、プロパティファイルではなくデータベースや専用の構成管理へ移す判断が現実的です。

⚠️ 注意: パスワードやトークンをプロパティファイルへ平文で置く場合、ファイル権限、リポジトリ除外、ログ出力の抑制を合わせて考えます。秘密情報は環境変数やシークレット管理と組み合わせるほうが扱いやすくなると言えるでしょう。

カスタマイズ方法

プロパティファイルのカスタマイズでは、既定値の継承、読み込み経路の切り替え、バリデーションの追加が中心になります。設定を増やすほど、単に値を読み込むだけでなく、欠落や型変換の失敗を早めに検出する仕組みが必要です。

そのため、カスタマイズではPropertiesを直接あちこちで読むより、設定を読み込む専用クラスへ集約すると管理しやすくなります。AppConfigのようなクラスを用意し、intbooleanへの変換もそこで行うと、呼び出し側のコードがすっきりするのが基本です。

プロパティの継承

Propertiesは、デフォルト値を持つ親プロパティを指定できます。環境共通の設定を親に置き、開発環境や本番環境ごとの差分だけを子に置くと、重複を減らせます。

import java.util.Properties;

public class PropertyInheritance {
    public static void main(String[] args) {
        // 親プロパティ
        Properties parentProperties = new Properties();
        parentProperties.setProperty("key1", "parentValue1");
        parentProperties.setProperty("key2", "parentValue2");

        // 子プロパティ
        Properties childProperties = new Properties(parentProperties);
        childProperties.setProperty("key2", "childValue2");
        childProperties.setProperty("key3", "childValue3");

        // 子プロパティを用いて値を取得
        String value1 = childProperties.getProperty("key1");
        String value2 = childProperties.getProperty("key2");
        String value3 = childProperties.getProperty("key3");

        // 結果を出力
        System.out.println("key1: " + value1); // 継承された値
        System.out.println("key2: " + value2); // 上書きされた値
        System.out.println("key3: " + value3); // 子プロパティに追加された値
    }
}

結果: 期待される出力は、key1が親の値、key2が子の値、key3が子で追加した値になる形です。

この仕組みでは、子にキーがなければ親の値が参照されます。一方、子に同じキーを設定すると親の値より優先されるため、デフォルト設定と環境別設定の関係を表現できます。

key1: parentValue1
key2: childValue2
key3: childValue3

結果: 期待される出力例は、key1が継承、key2が上書き、key3が追加として表示される3行です。

カスタムローダーの作成

読み込み処理をカスタマイズしたい場合は、専用メソッドや専用クラスを作りますが、これは押さえたい点です。たとえば、ファイルの存在確認、必須キーの検査、環境変数による上書き、ログ出力をまとめておくと、設定の使い方がアプリケーション全体でそろいます。

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class CustomLoader {
    public static Properties loadCustomProperties(String filePath) {
        Properties prop = new Properties();
        try (FileInputStream input = new FileInputStream(filePath)) {
            // カスタマイズした読み込み処理(例:コメント行を無視する)
            prop.load(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return prop;
    }

    public static void main(String[] args) {
        Properties properties = loadCustomProperties("config.properties");
        // 読み込んだプロパティを利用する処理
    }
}

結果: 期待される動作は、config.propertiesを読み込み、呼び出し元がPropertiesとして値を利用できる状態にすることです。

ただし、コメント行の無視は標準のloadでも行われます。実装パターンとしてよく見るのは、必須キーの欠落チェック、System.getenvによる上書き、Integer.parseIntによる型変換をこのローダーへ加える形です。

ℹ️ 補足: カスタマイズを進める場合も、最初は標準のPropertiesで足りるかを確認します。設定形式が複雑になった時点で、JSON、YAML、フレームワークの設定機構へ移す判断がしやすくなるのが目安です。

まとめ

Javaでプロパティファイルを読み込む使い方は、PropertiesloadgetPropertyの流れを押さえると理解しやすくなります。設定をソースコードから分離することで、環境ごとの差し替えや小さな変更を扱いやすくできます。

その一方で、文字コード、配置場所、秘密情報、データ量には注意が必要です。UTF-8の日本語を扱うならReader系APIを使い、英数字中心の設定ならInputStream系APIも選択肢になるのがポイントです。

これらを踏まえると、初心者は小さなconfig.propertiesから始め、読み込む処理、書き込む処理、カスタマイズの順に広げると無理なく学べます。サンプルコードをそのまま増やすのではなく、設定値の意味と変更頻度を見て、プロパティファイルへ切り出す対象を決めることが実用面で役立ちます。

一般に、プロパティファイルは「小さく、平坦で、変更される設定」に向いているのが一般的です。複雑な階層、配列、大量データ、秘密情報が中心になる場合は、別の形式や管理基盤と組み合わせるほうが保守しやすくなります。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。