Полезная информация

Exploring Java

Previous: 9.4 Vectors and HashtablesChapter 9
Basic Utility Classes
Next: 9.6 The Security Manager
 

9.5 Properties

The java.util.Properties class is a specialized hashtable for strings. Java uses the Properties object to replace the environment variables used in other programming environments. You can use a Properties table to hold arbitrary configuration information for an application in an easily accessible format. The Properties object can also load and store information using streams (see Chapter 10 for information on streams).

Any string values can be stored as key/value pairs in a Properties table. However, the convention is to use a dot-separated naming hierarchy to group property names into logical structures, as is done with X resources on UNIX systems.[4] The java.lang.System class provides system-environment information in this way, through a system Properties table I'll describe shortly.

[4] Unfortunately, this is just a naming convention right now, so you can't access logical groups of properties as you can with X resources.

Create an empty Properties table and add String key/value pairs just as with any Hashtable:

Properties props = new Properties(); 
props.put("myApp.xsize", "52"); 
props.put("myApp.ysize", "79"); 

Thereafter, you can retrieve values with the getProperty() method:

String xsize = props.getProperty( "myApp.xsize" ); 

If the named property doesn't exist, getProperty() returns null. You can get an Enumeration of the property names with the propertyNames() method:

for ( Enumeration e = props.propertyNames(); e.hasMoreElements; ) { 
    String name = e.nextElement(); 
    ... 
} 

9.5.1 Default Values

When you create a Properties table, you can specify a second table for default property values:

Properties defaults; 
... 
Properties props = new Properties( defaults ); 

Now when you call getProperty(), the method searches the default table if it doesn't find the named property in the current table. An alternative version of getProperty() also accepts a default value; this value is returned if the property is not found in the current list or in the default list:

String xsize = props.getProperty( "myApp.xsize", "50" ); 

9.5.2 Loading and Storing

You can save a Properties table to an OutputStream using the save() method. The property information is output in flat ASCII format. Continuing with the above example, output the property information to System.out as follows:

props.save( System.out, "Application Parameters" ); 

System.out is a standard output stream similar to C's stdout. We could also save the information to a file by using a FileOutputStream as the first argument to save(). The second argument to save() is a String that is used as a header for the data. The above code outputs something like the following to System.out:

#Application Parameters 
#Mon Feb 12 09:24:23 CST 1997 
myApp.ysize=79 
myApp.xsize=52 

The load() method reads the previously saved contents of a Properties object from an InputStream:

FileInputStream fin; 
... 
Properties props = new Properties() 
props.load( fin ); 

The list() method is useful for debugging. It prints the contents to an OutputStream in a format that is more human-readable but not retrievable by load() (it truncates long lines with a "...").

9.5.3 System Properties

The java.lang.System class provides access to basic system environment information through the static System.getProperty() method. This method returns a Properties table that contains system properties. System properties take the place of environment variables in other programming environments. Table 9.7 summarizes system properties that are guaranteed to be defined in any Java environment.

Table 9.7: System Properties
System PropertyMeaning
java.vendorVendor-specific string
java.vendor.urlURL of vendor
java.versionJava version
java.homeJava installation directory
java.class.versionJava class version
java.class.pathThe class path
os.nameOperating-system name
os.archOperating-system architecture
os.versionOperating-system version
file.separatorFile separator (such as "/" or "\")
path.separatorPath separator (such as ":" or ";")
line.separatorLine separator (such as "\n" or "\r\n")
user.nameUser account name
user.homeUser's home directory
user.dirCurrent working directory

Applets are, by current Web browser conventions, prevented from reading the following properties: java.home, java.class.path, user.name, user.home, and user.dir. As you'll see in the next section, these restrictions are implemented by a SecurityManager object.

Your application can set system properties with the static method System.setProperty(). You can also set system properties when you run the Java interpreter, using the -D option:

%java -Dfoo=bar -Dcat=Boojum MyApp

Since it is common to use system properties to provide parameters like numbers and colors, Java provides some convenience routines for retrieving property values and parsing them into their appropriate types. The classes Boolean, Integer, Long, and Color each come with a "get" method that looks up and parses a system property. For example, Integer.getInteger("foo") looks for a system property called foo and returns it as an Integer. Color.getColor("foo") would parse the property as an RGB value and return a Color object.

9.5.4 Observers and Observables

The java.util.Observer interface and java.util.Observable class are relatively small utilities, but they provide a peek at a fundamental design pattern. The concept of observers and observables is part of the MVC (Model View Controller) framework. It is an abstraction that lets a number of client objects (the observers) be notified whenever a certain object or resource (the observable) changes in some way. We will see this pattern used extensively in Java's event mechanism and in the AWT image producer model.

The basic idea behind observers and observables is that the Observable object has a method that an Observer calls to register its interest. When a change happens, the Observable sends a notification by calling a method in each of the Observers. The observers implement the Observer interface, which specifies the method (update()) to invoke.

In the following example, we create a MessageBoard object that holds a String message. MessageBoard extends Observable, from which it inherits the mechanism for registering and notifying observers; all the MessageBoard has to do is call notifyObservers() with the new message as an argument whenever the message changes. To observe the MessageBoard, we have Student objects that implement the Observer interface so that they can be notified when the message changes.

import java.util.*;

public class MessageBoard extends Observable {
    private String message;

    public String getMessage() {
        return message;
    }
    public void changeMessage( String message ) {
        this.message = message;
        setChanged();
        notifyObservers( message );
    }
    public static void main( String [] args ) {
        MessageBoard board = new MessageBoard();
        Student bob = new Student();
        Student joe = new Student();
        board.addObserver( bob );
        board.addObserver( joe );
        board.changeMessage("More Homework!");
    }
}

class Student implements Observer {
    public void update(Observable o, Object arg) {
        System.out.println( "Message board changed: " + arg );
    }
}
Our MessageBoard object extends Observable, which provides a method called addObserver(). Each of our Student objects registers itself using this method and receives updates via its update() method. When a new message string is set, using the MessageBoard's changeMessage() method, the Observable calls the setChanged() and notifyObservers() methods to notify the observers. notifyObservers() can take as an argument an Object to pass along as an indication of the change. This object, in this case, the String containing the new message, is passed to the observer's update() method.

The main() method of MessageBoard creates a MessageBoard and registers two Student objects with it. Then it changes the message. When you run the code, you should see each Student object print the message as it is notified.

You can imagine how you could implement the observer/observable relationship yourself using a Vector to hold the list of observers. These classes are not so much of value in and of themselves, as for what they represent. In Chapter 13 and beyond, we'll see that the AWT event model extends this design patttern to use strongly typed notification objects and observers; these are events and event listeners.


Previous: 9.4 Vectors and HashtablesExploring JavaNext: 9.6 The Security Manager
9.4 Vectors and HashtablesBook Index9.6 The Security Manager

Other Books in this LibraryJava in a NutshellJava Language ReferenceJava AWTJava Fundamental ClassesExploring Java