Check out the new USENIX Web site.
FeatureUSENIX

 
 

using java

rao_prithvi
by Prithvi Rao
<prithvi+@ux4.sp.cs.cmu.edu>

Prithvi Rao is the co-founder of KiwiLabs, which specializes in software engineering methodology and Java/CORBA training. He has also worked on the development of the MACH OS and a real-time version of MACH. He is an adjunct faculty at Carnegie Mellon and teaches in the Heinz School of Public Policy and Management.

 

The Java platform provides the programmer with a core set of classes that are in "packages," and we have seen many examples (such as java.io and java.net) in previous articles.

The way data is stored and structured in your program can make the difference between a clean, elegant solution and a mass of unrecognizable tangled code. For example, we know that an instance variable of a class can take the place of data structures in other languages; also, an array can hold many copies of one type of data. Nevertheless, we sometimes require "data containers" that are more powerful and flexible than either of these options.

Java provides a set of "collection classes" as part of the java.util package that are ready-made solutions to common data-storage problems. We will examine a few of the collection classes in Java. I'll leave it to the reader to extrapolate the use of the remaining collections by understanding the ones presented here.

Specifically we present the Stack class, Abstract Dictionaries, Property Lists, and Random Numbers.

Collections Explained
Collections in Java are not type-specific and can hold any type of object. This makes a collection a very flexible storage medium. When an object is stored in a collection it is implicitly cast to an Object. (Recall that Object is the base class from which all other classes are derived.) The methods used to store and retrieve Objects are collection-specific. For purposes of consistency, an object retrieved from a collection is returned as an Object. In order to perform a useful action on the Object, it must be recast to a reference of its original type (or its superclass).

The flexibility of Java collections can also be a disadvantage. For instance, since the collections are not type-specific, there is no type checking when an object is added. Consequently a collection of Strings can have a Thread object added to it without the compiler of Java runtime catching it.

The correct programming paradigm for code recovering objects from collections is always to catch ClassCastException.

The Stack Class
The Stack class implements a last-in-first-out stack of Objects. Objects can be "pushed" onto the top of the stack, then "popped" off. The first object to be pushed onto the stack will be the last one to be popped, and vice versa. To facilitate these operations, the methods push and pop are provided.

Popping an object off the stack will remove it from the stack. If you wish to examine an object on the top without removing it, then you can use the method peek().

In general, in order to examine the contents of the stack, you can use the search() method. This will look at the elements of the stack for the Object supplied as a parameter using the Object.equals() method as a means of locating it. If it finds it, the search returns its position in the stack.

If the return value is 1, this means that the Object is the topmost item in the stack. A value of 2 suggests the second place, and so on. A value of -1 suggests that the Object is not on the stack.

Both pop() and peek() will generate an EmptyStackExpression if there is no Object on the stack. You should always perform a boolean check with the empty() method when popping Objects from the stack.

Abstract Dictionaries
The Dictionary class is an abstract class that provides methods to store and retrieve an Object indexed by a key rather than an index. All of its methods are abstract. (It is effectively an interface, being "extended" rather than "implemented.") This means that the precise algorithms used to map and store keys are determined within the subclasses.

The simplest manipulations are put() and get(). The put() method places the Object into the Dictionary in an appropriate place based on the key that has been supplied. If another Object has already been stored using the same key, the new Object is stored with that key, and the put() method returns the Object previously stored there. The get() method returns the Object stored under the key supplied. In both cases, get() and put(), if the position associated with the key supplied is not occupied, a value of null is returned.

This means that neither the key nor the element can be null, since null is used to indicate that an Object was not found in that location. Attempts to use null will result in an exception.

Objects can be removed from the Dictionary with remove(), which returns the object associated with the given key and removes it. The current number of Objects in the Dictionary can be determined with size(); the is Empty() method is a special case to test for a size of 0 (zero).

We know that abstract classes are not in themselves very useful, but the Dictionary class is the parent class of two other very useful classes: HashTable and Properties.

Properties Lists
The Properties class builds on HashTable to provide an interface to a set of key/value pairs, both of which are strings. The most obvious place this is used is for the list of system properties with System.getProperty(). Although the method names used to manipulate the property list are specific to the Properties class, they all use the HashTable methods to store and retrieve data.

The no-argument constructor creates an empty property list. You can use put() to populate this list. The alternative constructor takes a default Properties list. If the requested key is not found in the current Properties object, then it is searched for in the default list. Note that the default list can itself have a default list, etc. It is not possible to change the default property list after construction.

The simplest thing to do with a Properties object is to query it with getProperty(). You supply the key, and it returns the matching value String (or null if not found). The alternative form allows you to supply a default value to be returned instead of null if the key is not found.

The Properties class also has a useful feature that allows you to save a properties list to an output stream and recover it from an input stream (typically a file). The save() method writes the list to the given stream. It is acceptable to supply a single-line comment that is placed at the start of the file. These properties can subsequently be read into a Properties object with load().

All of the properties can be recovered as an enumeration with the propertyNames() method or listed on a given print stream with list().

Random Numbers
The Random class permits the user to create and manipulate a pseudo-random-number generator. The argument constructor provides a random-number generator seeded with a value based on the current time. Alternatively, it is possible to set your own "long" seed value in the constructor or later with setSeed().

Once you have your Random object, you can generate uniformly distributed pseudo-random numbers of various types: int, long, float, double. In each case, the value generated will be between the minimum and maximum values for the given type, for example Integer.MIN_VALUE or Integer.MAX_VALUE.

If you do not wish to deal with all the overhead of object creation and destruction, it is possible to use the static method random() in the Math class. This returns a double value that can be converted into the desired type.

Example Using the Properties Collection Class

This program displays the system properties specified as input parameters or, if no input is given, all the system properties.

package java4cpp.collections;
import java.util.*;

public class SystemProperties {

        public static void main(String[] args) {
     if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i] + ": " +
                System.getProperty(args[i], "not found"));

         }

     } else {
        // dump all the system properties
        Properties sysProps = System.getProperties();
        Enumeration e = sysProps.propertyNames();
            while(e.hasMoreElements() ) {
                 String propName = (String) e.nextElement();
                     System.out.println(propName + ": " +
                        sysProps.getProperty(propName));

            }

        }

    }

}

Compile the program: javac SystemProperties.java
Run the program: java SystemProperties

When there are no input arguments, the output describes the native environment on which the program has run and the implementation of the JVM used. The following output or one similar will be displayed if you run this program.

user.language: en
user.name: prithvi
java.home: /usr/local/jdk1.2.2/bin
file.encoding.pkg: sun.io
java.version: 1.2.2
file separator: /
line.separator:
user.region: US
file.encoding: 8859_1
user.timezone: EST
path.separator: :

Summary
We have examined some of the collections that are part of Java. Collections can be organized into abstract structures such as sets, bags, lists, stacks, trees, queues, hash tables, and many others. When selecting a collection class, we have seen that there are abstract classes that must be extended or that simply use one of the data structures already encapsulated by any of the core collection class (such as Properties in the example above). No matter which you choose, there is a greater chance that your code will be more elegant.
The overhead of object creation and destruction can result in a possible performance degradation, but if used wisely this too can be ameliorated.


 

?Need help? Use our Contacts page.
Last changed: 1 Aug. 2000 mc
Using Java index
;login: index
USENIX home