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 setsyou can only hold primitives and Strings, and the length of each stored String cant be longer than 8K (not tiny, but you dont 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, its typical to create a single node named after your class and store the information there. Heres 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, youll usually use getClass( ). You dont need to use the current class as the node identifier, but thats the usual practice.
Once you create the node, its 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 youre used to keys( ) in the collections library. Here, theyre 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 isnt any entry for that key value. While iterating through a set of keys, you always know theres an entry, so using null as the default is safe, but normally youll be fetching a named key, as in:
prefs.getInt("Companions", 0));
In the normal case, youll 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 youll see that the UsageCount does indeed increment every time you run the program, but where is the data stored? Theres 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 its 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 dont have to worry about how it works from one system to another.
Theres more to the Preferences API than shown here. Consult the JDK documentation, which is fairly understandable, for further details.