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();
...
}
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" );
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 "...").
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.
| System Property | Meaning |
|---|---|
java.vendor | Vendor-specific string |
java.vendor.url | URL of vendor |
java.version | Java version |
java.home | Java installation directory |
java.class.version | Java class version |
java.class.path | The class path |
os.name | Operating-system name |
os.arch | Operating-system architecture |
os.version | Operating-system version |
file.separator | File separator (such as "/" or "\") |
path.separator | Path separator (such as ":" or ";") |
line.separator | Line separator (such as "\n" or "\r\n") |
user.name | User account name |
user.home | User's home directory |
user.dir | Current 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.
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.