これまでに皆さんは、プログラムの構成データを保存する必要に迫られたものの、データをどこに保存してよいかわからなかったという経験はありますか。この情報についてはプロパティー・ファイルやリソース・バンドルを利用できますが、ファイルを保存する標準的な場所をJavaプラットフォームが指定することはありませんでした。これが、JSR 10で大きく変わりました。JSR 10は、java.util.prefs パッケージをJava 1.4 APIに追加しました。ストレージ・メカニズムは、実装ごとに固有の詳細事項で、プログラマーが知る必要のない、あるいは気にかける必要のないものでもあります。Windowsプラットフォームでは、その場所はWindows Registryです。皆さんはRegistryにおいて自由な権限を持ってはいませんが、すべてのアプリケーションのために共通ルート・ノードからのアクセスはできます。
適切に命名されているPreferences クラスは、プリファレンスに取り組むための基本フレームワークをもたらします。このクラスは、2組のプリファレンス・セットの一方、すなわちユーザー・プリファレンス用またはシステム・プリファレンス用、と連携するための一連の静的および抽象メソッドを提供します。静的メソッドを使用して、WindowsPreferences クラスのようなプラットフォーム固有の実装を得ることができます。次に、そのプラットフォーム固有の実装によって実装される抽象メソッドを使用して作業を行うことができます。
パッケージごとにプログラムのプリファレンスをグループ分けして、他のアプリケーションとのネーミングの競合を避けるのは、良い習慣です。Preferences オブジェクトを必要とする場合には、ただパッケージ名を伝えるだけですみます。非静的メソッドの場合には、自身への参照子 (this)を渡すことができ、リスト1に示すようにプログラムがパッケージを判断します。
リスト1. 非静的メソッドからのPreferencesオブジェクトの取り出し
Preferences userPrefs = Preferences.userNodeForPackage(this);
Preferences sysPrefs = Preferences.systemNodeForPackage(this);
|
ただし、静的メソッドにある場合には、リスト2に示すように、ルート・ノードを取得してパッケージを自ら提供する必要があります。
リスト2. 静的メソッドからのPreferencesオブジェクトの取り出し
Preferences userPrefs = Preferences.userRoot().node("/net/zukowski/ibm");
Preferences sysPrefs = Preferences.systemRoot().node("/net/zukowski/ibm");
|
作業を行うノードが得られたら、都合の良いときに設定をセットし、取得し、削除し、ダンプすることができます。Preferences オブジェクトを、ツリーのような形状の構造でキーを構成する1つの巨大なキー値ハッシュ・テーブルと考えてみてください。これはCollections Frameworkに属するものではありませんが (Collections Frameworkの詳細については、参考文献を参照してください)。
まず、プリファレンスを格納する方法から検討していきます。Preferences クラスは、値を格納するために、以下に示す一連のput() メソッドを提供します。基本のストリングのサポートに加えて、ブール、倍精度、浮動、整数、長精度、バイト配列 (直列化を考えてみてください) を格納できます。これらのヘルパー・メソッドは、適切なデータ型をとり、データをストリングとしてストアするために必要な変換を行います。
-
put(String key, String value) -
putBoolean(String key, boolean value) -
putByteArray(String key, byte value[]) -
putDouble(String key, double value) -
putFloat(String key, float value) -
putInt(String key, int value) -
putLong(String key, long value)
すべてのput() メソッドはvoidを返します。ストレージ・メカニズムが利用できない場合には、BackingStoreException がスローされます。
注 : 特定のプリファレンスのキーは、Preferences.MAX_KEY_LENGTH (80) バイトの長さに制限されていますが、値はPreferences.MAX_VALUE_LENGTH (8192) バイトに制限されています。
特定のプリファレンスの取得は、以下に示す一連のget() メソッドを通じて行われます。書き込みと同様に、サポート対象のデータ型ごとに異なるメソッドがあります。ただし、取得についての1つの相違点は、補助記憶装置が使用できない場合、あるいはまだ期待しているものが保存されていない場合に、デフォルト値を提供する必要があるということです。この要件により、プログラムに少なくとも妥当なデフォルト設定が返されることが保証されます。
-
get(String key, String default) -
getBoolean(String key, boolean default) -
getByteArray(String key, byte default[]) -
getDouble(String key, double default) -
getFloat(String key, float default) -
getInt(String key, int default) -
getLong(String key, long default)
プリファレンス名に確信がない場合には、keys() メソッドでノードに関連づけられているキーのリストを見つけることができます。このメソッドは、ノードのString[] を返します。個々のプリファレンスを取得・格納し、キーのリストを取得することに加え、clear()、remove()、およびremoveNode() でノードと値を削除することもできます。
システムが供給している補助記憶装置の外部でプリファレンスを保存して復元する場合には、XML形式のドキュメントでこれを行うことができます。exportNode() でノードをエクスポートすることも、exportSubtree() でサブツリー全体をエクスポートすることも可能です。情報は、UTF-8形式で保存されます。次に、情報を復元する場合には、importPreferences() メソッドを使います。
詮索好きは身を誤ってしまうこともあるかもしれませんが、プリファレンスが変更される時点を知ることに関心があるのなら、動作への直接の影響を心配することなくNodeChangeListener またはPreferenceChangeListener を登録することができます。NodeChangeListener は、ノードが追加および削除されたときに通知する役割を果たし、PreferenceChangeListener は値の変化を知らせます。いずれも、add/removeNodeChangeListener(NodeChangeListener) およびadd/removePreferenceChangeListener() メソッドの基本JavaBeansコンポーネント・イベント処理構造に従っています。基本的に、リスナーを実装し、次いでリスナーを登録すると、将来の変更について知ることができます。
ただこれだけのことで、どうということはありません。リスト3では、皆さんが新機能を実際に試すことができるように完全な例を紹介しています (参考文献からダウンロードすることもできます)。このプログラムは実行後にクリーンアップを行うので、レジストリーの値を知りたい場合には、最後にあるクリーンアップ・コードをコメント化してください。
リスト3. 完全な例
package net.zukowski.ibm;
import java.io.*;
import java.util.prefs.*;
public class Prefs {
public static void main(String args[]) {
String denominations[] = {"One", "Two", "Five", "Ten", "Twenty"};
String pictures[] = {"Washington", "Jefferson", "Lincoln", "Hamilton", "Jackson"};
NodeChangeListener nodeChangeListener = new NodeChangeListener() {
public void childAdded(NodeChangeEvent event) {
Preferences parent = event.getParent();
Preferences child = event.getChild();
System.out.println(parent.name() + " has a new child " +
child.name());
}
public void childRemoved(NodeChangeEvent event) {
Preferences parent = event.getParent();
Preferences child = event.getChild();
System.out.println(parent.name() + " lost a child " +
child.name());
}
};
PreferenceChangeListener preferenceChangeListener = new PreferenceChangeListener() {
public void preferenceChange(PreferenceChangeEvent event) {
String key = event.getKey();
String value = event.getNewValue();
Preferences node = event.getNode();
System.out.println(node.name() + " now has a value of " + value + " for " + key);
}
};
// Look up user root
Preferences prefs = Preferences.userRoot().node("/net/zukowski/ibm");
// Add listeners
prefs.addNodeChangeListener(nodeChangeListener);
prefs.addPreferenceChangeListener(preferenceChangeListener);
// Save a bunch of key-value pairs
for (int i=0, n=denominations.length; i < n; i++) {
prefs.put(denominations[i], pictures[i]);
}
// Display all the entries
try {
String keys[] = prefs.keys();
for (int i=0, n=keys.length; i < n; i++) {
System.out.println(keys[i] + ": " + prefs.get(keys[i], "Unknown"));
}
} catch (BackingStoreException e) {
System.err.println("Unable to read backing store: " + e);
}
// Create child
Preferences child = Preferences.userRoot().node("/net/zukowski/ibm/foo");
// Save to XML file
try {
FileOutputStream fos = new FileOutputStream("prefs.out");
prefs.exportNode(fos);
} catch (Exception e) {
System.err.println("Unable to export nodes: " + e);
}
// Clean up
try {
prefs.removeNode();
} catch (BackingStoreException e) {
System.err.println("Unable to access backing store: " + e);
}
}
}
|
-
JSR 10は、プリファレンス・サポートの基礎について説明しています。
-
Preferencesクラスについて理解を深めるには、API docs をお読みください。 -
Collections Framework は、コレクションを操作するための標準Javaアーキテクチャーについて説明しています。
- IBM alphaWorksXML Registry/Repository は、XMLアーティファクト向けサービスを提供するデータ管理システムを備えています。
- 「PropertyResourceBundleへの継承の導入」 (developerWorks、2001年5月) は、バンドルの再利用を最大限に高め、しかもリソース・バンドルの関係を促進する方法について説明しています。
-
developerWorks Javaテクノロジー・ゾーンで他のJava参考文献をご覧ください。

John Zukowskiは、JZ Ventures, Inc.の戦略的Javaコンサルティングを推進し、数多くのjGuruのコミュニティー主導のJava FAQsで常任指導者として活躍しています。最新の著書には、Apressから出版された「 Java Collections」および「 Definitive Guide to Swing for Java 2」 (第2版) があります。彼のメール・アドレスはjaz@zukowski.net です。