Most programs can be configured by their users. The programs must then save the user preferences and restore them when the app starts again. You already saw how a Java Web Start app can use a persistent store for that purpose. However, SDK 1.4 introduced a different and more powerful mechanism for local apps. We will describe that mechanism, but first we will cover the much simpler approach for storing configuration information that Java apps have traditionally taken.

Property Sets

A property set is a data structure that stores key/value pairs. Property sets are often used for storing configuration information. Property sets have three particular characteristics:

The Java platform class that implements a property set is called Properties. Property sets are useful in specifying configuration options for programs. For example,

Properties settings = new Properties();
settings.put("font", "Courier");
settings.put("size", "10");
settings.put("message", "Hello, World");

Use the store method to save this list of properties to a file. Here, we just print the property set to the standard output. The second argument is a comment that is included in the file.

FileOutputStream out
 = new FileOutputStream("Myprog.properties");
settings.store(out, "Myprog Properties");

The sample set gives the following output.

#Myprog Properties
#Sun Jul 14 07:22:52 2002
font=Courier size=10
message=Hello, World

To load the properties from a file, use

FileInputStream in
 = new FileInputStream("Myprog.properties");
settings.load(in);

We'll put this technique to work so that your users can customize the NotHelloWorld program to their hearts' content. We'll allow them to specify the following in the configuration file CustomWorld.properties:

If the user doesn't specify some of the settings, we will provide defaults. The Properties class has two mechanisms for providing defaults. First, whenever you look up the value of a string, you can specify a default that should be used automatically when the key is not present.

String font = settings.getProperty("font", "Courier");

If there is a "font" property in the property table, then font is set to that string. Otherwise, font is set to "Courier". If you find it too tedious to specify the default in every call to getProperty, then you can pack all the defaults into a secondary property set and supply that in the constructor of your lookup table.

Properties defaultSettings = new Properties();
defaultSettings.put("font", "Courier");
defaultSettings.put("size", "10");
defaultSettings.put("color.red", "0");
. . .
Properties settings = new Properties(defaultSettings);
FileInputStream in
 = new FileInputStream("CustomWorld.properties");
settings.load(in);
. . .

Yes, you can even specify defaults to defaults if you give another property set parameter to the defaultSettings constructor, but it is not something one would normally do. is the customizable "Hello, Custom World" program. Just edit the .properties file to change the program's appearance to the way you want (see ).

The customized Hello World program

Java graphics 10fig17Java graphics notes_icon

Properties are simple table without a hierarchical structure. It is common to introduce a fake hierarchy with key names such as color.red, color.green, and so on. But there are no methods in the Properties class that help organize such a hierarchy. If you store complex configuration information, you should use the Preferences class instead-see the next section.Java graphics notes_icon

The Properties class extends the Hashtable class. That means that all methods of Hashtable are available to Properties objects. Some methods are useful. For example, size returns the number of possible properties (well, it isn't that nice-it doesn't count the defaults). Similarly, keys returns an enumeration of all keys, except for the defaults. There is also a second function, called propertyNames, that returns all keys. The put function is downright dangerous. It doesn't check that you put strings into the table. Does the is-a rule for using inheritance apply here? Is every property set a hash table? Not really. That these are true is really just an implementation detail. Maybe it is better to think of a property set as having a hash table. But then the hash table should be a private instance variable. Actually, in this case, a property set uses two hash tables: one for the defaults and one for the nondefault values. We think a better design would be the following:

class Properties
{
 public String getProperty(String) { . . . }
 public void put(String, String) { . . . }
 . . .
 private Hashtable nonDefaults;
 private Hashtable defaults;
}

We don't want to tell you to avoid the Properties class in the Java library. Provided you are careful to put nothing but strings in it, it works just fine. But think twice before using "quick and dirty" inheritance in your own programs.

Example CustomWorld.java

 1. import java.awt.*;
 2. import java.awt.event.*;
 3. import java.util.*;
 4. import java.io.*;
 5. import javax.swing.*;
 6.
 7. /**
 8. This program demonstrates how to customize a "Hello, World"
 9. program with a properties file.
10. */
11. public class CustomWorld
12. {
13. public static void main(String[] args)
14. {
15. CustomWorldFrame frame = new CustomWorldFrame();
16. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
17. frame.show();
18. }
19. }
20.
21. /**
22. This frame displays a message. The frame size, message text,
23. font, and color are set in a properties file.
24. */
25. class CustomWorldFrame extends JFrame
26. {
27. public CustomWorldFrame()
28. {
29. Properties defaultSettings = new Properties();
30. defaultSettings.put("font", "Monospaced");
31. defaultSettings.put("width", "300");
32. defaultSettings.put("height", "200");
33. defaultSettings.put("message", "Hello, World");
34. defaultSettings.put("color.red", "0 50 50");
35. defaultSettings.put("color.green", "50");
36. defaultSettings.put("color.blue", "50");
37. defaultSettings.put("ptsize", "12");
38.
39. Properties settings = new Properties(defaultSettings);
40. try
41. {
42. FileInputStream in
43. = new FileInputStream("CustomWorld.properties");
44. settings.load(in);
45. }
46. catch (IOException exception)
47. {
48. exception.printStackTrace();
49. }
50.
51. int red = Integer.parseInt(
52. settings.getProperty("color.red"));
53. int green = Integer.parseInt(
54. settings.getProperty("color.green"));
55. int blue = Integer.parseInt(
56. settings.getProperty("color.blue"));
57.
58. Color foreground = new Color(red, green, blue);
59.
60. String name = settings.getProperty("font");
61. int ptsize = Integer.parseInt(
62. settings.getProperty("ptsize"));
63. Font f = new Font(name, Font.BOLD, ptsize);
64.
65. int hsize = Integer.parseInt(
66. settings.getProperty("width"));
67. int vsize = Integer.parseInt(
68. settings.getProperty("height"));
69. setSize(hsize, vsize);
70. setTitle(settings.getProperty("message"));
71.
72. JLabel label
73. = new JLabel(settings.getProperty("message"),
74. SwingConstants.CENTER);
75. label.setFont(f);
76. label.setForeground(foreground);
77. getContentPane().add(label);
78. }
79. }

java.util.Properties 1.0

Java graphics api_icon