Preferences
JDK 1.4 introduced the Preferences API, which is much closer to persistence than object serialization because it automatically stores and retrieves your information. However, its use is restricted to small and limited data sets—you can only hold primitives and Strings, and the length of each stored String can’t be longer than 8K (not tiny, but you don’t want to build anything serious with it, either). As the name suggests, the Preferences API is designed to store and retrieve user preferences and program-configuration settings.
Preferences are key-value sets (like Maps) stored in a hierarchy of nodes. Although the node hierarchy can be used to create complicated structures, it’s typical to create a single node named after your class and store the information there. Here’s a simple example:
//: c12:PreferencesDemo.java
import java.util.prefs.*;
import java.util.*;
public class PreferencesDemo {
public static void main(String[] args) throws Exception {
Preferences prefs = Preferences
.userNodeForPackage(PreferencesDemo.class);
prefs.put("Location", "Oz");
prefs.put("Footwear", "Ruby Slippers");
prefs.putInt("Companions", 4);
prefs.putBoolean("Are there witches?", true);
int usageCount = prefs.getInt("UsageCount", 0);
usageCount++;
prefs.putInt("UsageCount", usageCount);
Iterator it = Arrays.asList(prefs.keys()).iterator();
while(it.hasNext()) {
String key = it.next().toString();
System.out.println(key + ": "+ prefs.get(key, null));
}
// You must always provide a default value:
System.out.println(
"How many companions does Dorothy have? " +
prefs.getInt("Companions", 0));
}
} ///:~
Here, userNodeForPackage( ) is used, but you could also choose systemNodeForPackage( ); the choice is somewhat arbitrary, but the idea is that “user” is for individual user preferences, and “system” is for general installation configuration. Since main( ) is static, PreferencesDemo.class is used to identify the node, but inside a non-static method, you’ll usually use getClass( ). You don’t need to use the current class as the node identifier, but that’s the usual practice.
Once you create the node, it’s available for either loading or reading data. This example loads the node with various types of items and then gets the keys( ). These come back as a String[], which you might not expect if you’re used to keys( ) in the collections library. Here, they’re converted to a List that is used to produce an Iterator for printing the keys and values. Notice the second argument to get( ). This is the default value that is produced if there isn’t any entry for that key value. While iterating through a set of keys, you always know there’s an entry, so using null as the default is safe, but normally you’ll be fetching a named key, as in:
prefs.getInt("Companions", 0));
In the normal case, you’ll want to provide a reasonable default value. In fact, a typical idiom is seen in the lines:
int usageCount = prefs.getInt("UsageCount", 0);
usageCount++;
prefs.putInt("UsageCount", usageCount);
This way, the first time you run the program, the UsageCount will be zero, but on subsequent invocations it will be nonzero.
When you run PreferencesDemo.java you’ll see that the UsageCount does indeed increment every time you run the program, but where is the data stored? There’s no local file that appears after the program is run the first time. The Preferences API uses appropriate system resources to accomplish its task, and these will vary depending on the OS. In Windows, the registry is used (since it’s already a hierarchy of nodes with key-value pairs). But the whole point is that the information is magically stored for you so that you don’t have to worry about how it works from one system to another.
There’s more to the Preferences API than shown here. Consult the JDK documentation, which is fairly understandable, for further details.