'; zhtm += ''; zhtm += '

' + pPage + ''; zhtm += '
'; window.popUpWin.document.write(zhtm); window.popUpWin.document.close(); // Johnny Jackson 4/28/98 } //--> Java 1.2 Unleashed -- Ch 11 -- Using the Utility and Math Packages


Java 1.2 Unleashed

Contents


- 11 -

Using the Utility and Math Packages


The java.util family of packages and the java.math package provide a number of classes and interfaces that can be used to simplify the development of window and console applications, applets, or just about any Java code that you write. These utility classes include the new JDK 1.2 Collections API, as well as Java Archive (JAR), ZIP file, and MIME type support. The math classes provide support for large-number arithmetic. In this chapter you'll learn how to work with all the useful utility classes contained in the java.util, java.util.mime, java.util.zip, java.util.jar, and java.math packages. When you finish this chapter, you'll be able to make productive use of these classes in your own programs.

The java.util Package

The java.util package provides 34 classes and 13 interfaces that support the new Collections API, date/calendar operations, internationalization, change observation, parsing, random number generation, and basic event processing. These classes and interfaces are covered in the following subsections.

The Collections API

The most notable change to the java.util package in JDK 1.2 is the introduction of the classes and interfaces of the Collections API. These classes and interfaces provide an implementation-independent framework for manipulating collections of objects. We'll first review the pre-JDK 1.2 collections classes and interfaces. Then we'll cover the new classes and interfaces introduced with JDK 1.2.

Pre-JDK 1.2 Collections Classes and Interfaces

JDK 1.1 provided the Enumeration interface and the following six classes for working with collections of objects:

The Enumeration interface and the preceding six classes proved to be very valuable in working with different types of object collections. Their success inspired the JDK 1.2 Collections API. The following subsections cover the Enumeration interface and the six classes in the preceding list.

The Enumeration Interface

The Enumeration interface provides two methods for stepping through an indexed set of objects or values: hasMoreElements() and nextElement(). The hasMoreElements() method enables you to determine whether more elements are contained in an Enumeration object. The nextElement() method returns the nextElement() contained by an object.

Enumeration-implementing objects are said to be consumed by their use. This means that the Enumeration objects cannot be restarted to reaccess through the elements they contain. Their elements may be accessed only once.


NOTE: The Enumeration interface has been replaced by the Iterator interface in the JDK 1.2 Collections API. You can still use Enumeration, but it is being phased out.

The Vector Class

The Vector class provides the capability to implement a growable array. The array grows larger as more elements are added to it. The array may also be reduced in size after some of its elements have been deleted. This is accomplished using the trimToSize() method.

Vector operates by creating an initial storage capacity and then adding to this capacity as needed. It grows by an increment defined by the capacityIncrement variable. The initial storage capacity and capacityIncrement can be specified in Vector's constructor. A second constructor is used when you want to specify only the initial storage capacity. A third, default constructor specifies neither the initial capacity nor the capacityIncrement. This constructor lets Java figure out the best parameters to use for Vector objects. Finally, a fourth constructor was added with JDK 1.2 to create a Vector out of a Collection object.

The access methods provided by the Vector class support array-like operations and operations related to the size of Vector objects. The array-like operations allow elements to be added, deleted, and inserted into vectors. They also allow tests to be performed on the contents of vectors and specific elements to be retrieved. The size-related operations allow the byte size and number of elements of the vector to be determined, and the vector size to be increased to a certain capacity or trimmed to the minimum capacity needed. Consult the Vector API page for a complete description of these methods.


NOTE: The Vector class has been retrofitted in JDK 1.2 to extend the AbstractList class and implement the List interface.

VectorApp

The VectorApp program illustrates the use of vectors and the Enumeration interface. (See Listing 11.1.)

LISTING 11.1. THE SOURCE CODE OF THE VectorApp PROGRAM.

import java.lang.System;
import java.util.Vector;
import java.util.Enumeration;
public class VectorApp {
 public static void main(String args[]){
  Vector v = new Vector();
  v.addElement("one");
  v.addElement("two");
  v.addElement("three");
  v.insertElementAt("zero",0);
  v.insertElementAt("oops",3);
  v.insertElementAt("four",5);
  System.out.println("Size: "+v.size());
  Enumeration enum = v.elements();
  while (enum.hasMoreElements())
   System.out.print(enum.nextElement()+" ");
  System.out.println();
  v.removeElement("oops");
  System.out.println("Size: "+v.size());
  for(int i=0;i<v.size();++i)
   System.out.print(v.elementAt(i)+" ");
  System.out.println();
 }
}

The program creates a Vector object using the default constructor, and uses the addElement() method to add the strings "one", "two", and "three" to the vector. It then uses the insertElementAt() method to insert the strings "zero", "oops", and "four" at locations 0, 3, and 5 within the vector. The size() method is used to retrieve the vector size for display to the console window.

The elements() method of the Vector class is used to retrieve an enumeration of the elements that were added to the vector. A while loop is then used to cycle through and print the elements contained in the enumeration. The hasMoreElements() method is used to determine whether the enumeration contains more elements. If it does, the nextElement() method is used to retrieve the object for printing.

The removeElement() of the Vector class is used to remove the vector element containing the string "oops". The new size of the vector is displayed and the elements of the vector are redisplayed. The for loop indexes each element in the vector using the elementAt() method.

The output of the VectorApp program is as follows:

Size: 6
zero one two oops three four
Size: 5
zero one two three four

The Stack Class

The Stack class provides the capability to create and use storage objects called stacks within your Java programs. You store information by pushing it onto a stack, and remove and retrieve information by popping it off the stack. Stacks implement a last-in-first-out storage capability. The last object pushed onto a stack is the first object that can be retrieved from the stack. The Stack class extends the Vector class.

The Stack class provides a single default constructor, Stack(), that is used to create an empty stack.

Objects are placed on the stack using the push() method and retrieved from the stack using the pop() method. The search() method allows you to search through a stack to see if a particular object is contained on the stack. The peek() method returns the top element of the stack without popping it off. The empty() method is used to determine whether a stack is empty. The pop() and peek() methods both throw the EmptyStackException if the stack is empty. Use of the empty() method can help to avoid the generation of this exception.

StackApp

The StackApp program demonstrates the operation of a stack (see Listing 11.2). It creates a Stack object and then uses the push() method to push the strings "one", "two", and "three" onto the stack. Because the stack operates in last-in-first-out fashion, the top of the stack is the string "three". This is verified by using the peek() method. The contents of the stack are then popped off and printed using a while loop. The empty() method is used to determine when the loop should terminate. The pop() method is used to pop objects off the top of the stack.

LISTING 11.2. THE SOURCE CODE OF THE StackApp PROGRAM.

import java.lang.System;
import java.util.Stack;
public class StackApp {
 public static void main(String args[]){
  Stack s = new Stack();
  s.push("one");
  s.push("two");
  s.push("three");
  System.out.println("Top of stack: "+s.peek());
  while (!s.empty())
   System.out.println(s.pop());
 }
}

The output of the StackApp program is as follows:

Top of stack: three
three
two
one

The BitSet Class

The BitSet class is used to create objects that maintain a set of bits. The bits are maintained as a growable set. The capacity of the bit set is increased as needed. Bit sets are used to maintain a list of flags that indicate the state of each element of a set of conditions. Flags are boolean values that are used to represent the state of an object.

Two BitSet constructors are provided. One allows the initial capacity of a BitSet object to be specified. The other is a default constructor that initializes a BitSet to a default size.

The BitSet access methods provide and, or, and exclusive or logical operations on bit sets, enable specific bits to be set and cleared, and override general methods declared for the Object class.

BitSetApp

The BitSetApp program demonstrates the operation of bit sets. See Listing 11.3.

LISTING 11.3. THE SOURCE CODE OF THE BitSetApp PROGRAM.

import java.lang.System;
import java.util.BitSet;
public class BitSetApp {
 public static void main(String args[]){
  int size = 8;
  BitSet b1 = new BitSet(size);
  for(int i=0;i<size;++i) b1.set(i);
  BitSet b2 = (BitSet) b1.clone();
  for(int i=0;i<size;i=i+2) b2.clear(i);
  System.out.print("b1: ");
  for(int i=0;i<size;++i) System.out.print(b1.get(i)+" ");
  System.out.print("\nb2: ");
  for(int i=0;i<size;++i) System.out.print(b2.get(i)+" ");
  System.out.println();
  System.out.println("b1: "+b1);
  System.out.println("b2: "+b2);
  b1.xor(b2);
  System.out.println("b1 xor b2 = "+b1);
  b1.and(b2);
System.out.println("b1 and b2 = "+b1);
  b1.or(b2);
  System.out.println("b1 or b2 = "+b1);
 }
}

The program begins by creating a BitSet object, b1, of size 8. It executes a for statement to index through b1 and set each bit in the bit set. It then uses the clone() method to create an identical copy of b1 and assign it to b2. Another for statement is executed to clear every even-numbered bit in b2. The values of the b1 and b2 bit sets are then printed. This results in the display of two lists of boolean values. The bit sets are printed as objects, resulting in a set-oriented display. Only the bits with true boolean values are identified as members of the displayed bit sets.

The xor() method is used to compute the exclusive or of b1 and b2, updating b1 with the result. The new value of b1 is then displayed.

The and() method is used to calculate the logical and of b1 and b2, again, updating b1 with the result and displaying b1's new value.

Finally, the logical or of b1 and b2 is computed, using the or() method. The result is used to update b1, and b1's value is displayed.

The output of BitSetApp is as follows:

b1: true true true true true true true true
b2: false true false true false true false true
b1: {0, 1, 2, 3, 4, 5, 6, 7}
b2: {1, 3, 5, 7}
b1 xor b2 = {0, 2, 4, 6}
b1 and b2 = {}
b1 or b2 = {1, 3, 5, 7}

The Dictionary, Hashtable, and Properties Classes

The Dictionary, Hashtable, and Properties classes are three generations of classes that implement the capability to provide key-based data storage and retrieval. The Dictionary class is the abstract superclass of Hashtable, which is, in turn, the superclass of Properties.

Dictionary

Dictionary provides the abstract functions used to store and retrieve objects by key-value associations. The class allows any object to be used as a key or value. This provides great flexibility in the design of key-based storage and retrieval classes. Hashtable and Properties are two examples of these classes.

The Dictionary class can be understood using its namesake abstraction. A hard-copy dictionary maps words to their definitions. The words can be considered the keys of the dictionary, and the definitions are the values of the keys. Java dictionaries operate in the same fashion. One object is used as the key to access another object. This abstraction will become clearer as you investigate the Hashtable and Properties classes.

The Dictionary class defines several methods that are inherited by its subclasses. The elements() method is used to return an Enumeration object containing the values of the key-value pairs stored within the dictionary. The keys() method returns an enumeration of the dictionary keys. The get() method is used to retrieve an object from the dictionary based on its key. The put() method puts a Value object in the dictionary and indexes it using a Key object. The isEmpty() method determines whether a dictionary contains any elements, and the size() method identifies the dictionary's size in terms of the number of elements it contains. The remove() method deletes a key-value pair from the dictionary, based on the object's key.


NOTE: The Dictionary class has been rendered obsolete by the Map interface, as of JDK 1.2. However, its Hashtable and Properties subclasses are still in use.

Hashtable

The Hashtable class implements a hash table data structure. A hash table indexes and stores objects in a dictionary using hash codes as the objects' keys. Hash codes are integer values that identify objects. They are computed in such a manner that different objects are very likely to have different hash values and therefore different dictionary keys.

The Object class implements the hashCode() method. This method allows the hash code of an arbitrary Java object to be calculated. All Java classes and objects inherit this method from Object. The hashCode() method is used to compute the hash code key for storing objects within a hash table. Object also implements the equals() method. This method is used to determine whether two objects with the same hash code are, in fact, equal.

The Java Hashtable class is very similar to the Dictionary class from which it is derived. Objects are added to a hash table as key-value pairs. The object used as the key is hashed, using its hashCode() method, and the hash code is used as the actual key for the value object. When an object is to be retrieved from a hash table, using a key, the key's hash code is computed and used to find the object.

The Hashtable class provides three constructors. The first constructor allows a hash table to be created with a specific initial capacity and load factor. The load factor is a float value between 0.0 and 1.0 that identifies the percentage of hash table usage that causes the hash table to be rehashed into a larger table. For example, suppose a hash table is created with a capacity of 100 entries and a 0.70 load factor. When the hash table is 70 percent full, a new, larger hash table will be created, and the current hash table entries will have their hash values recalculated for the larger table.

The second Hashtable constructor just specifies the table's initial capacity and ignores the load factor. The default hash table constructor does not specify either hash table parameter.

The access methods defined for the Hashtable class allow key-value pairs to be added to and removed from a hash table, to search the hash table for a particular key or object value, to create an enumeration of the table's keys and values, to determine the size of the hash table, and to recalculate the hash table as needed. Many of these methods are inherited or overridden from the Dictionary class.

HashApp

The HashApp program illustrates the operation and use of hash tables. See Listing 11.4.

LISTING 11.4. THE SOURCE CODE OF THE HashApp PROGRAM.

import java.lang.System;
import java.util.Hashtable;
import java.util.Enumeration;
public class HashApp {
 public static void main(String args[]){
  Hashtable h = new Hashtable();
  h.put("height","6 feet");
  h.put("weight","200 pounds");
  h.put("eye color","blue");
  h.put("hair color","brown");
  System.out.println("h: "+h);
  Enumeration enum = h.keys();
  System.out.print("keys: ");
  while (enum.hasMoreElements()) System.out.print(enum.nextElement()+", Â");
  System.out.print("\nelements: ");
  enum = h.elements();
  while (enum.hasMoreElements()) System.out.print(enum.nextElement()+", Â");
  System.out.println();
  System.out.println("height: "+h.get("height"));
  System.out.println("weight: "+h.get("weight"));
  System.out.println("eyes: "+h.get("eye color"));
  System.out.println("hair: "+h.get("hair color"));
  h.remove("weight");
  System.out.println("h: "+h);
 }
}

The program begins by creating a Hashtable object using the default constructor. It then adds four key-value pairs to the hash table using the put() method. The hash table is then printed using the default print method for objects of class Hashtable.

The keys() method is used to create an enumeration of the hash table's keys. These keys are then printed one at a time by indexing through the enumeration object.

The elements() method is used to create an enumeration of the hash table's values. This enumeration is printed in the same way as the key enumeration.

The values of the hash table are again displayed by using the get() method to get the values corresponding to specific key values.

Finally, the remove() method is used to remove the key-value pair associated with the weight key, and the hash table is reprinted using the default print convention.

The program output is as follows:

h: {height=6 feet, weight=200 pounds, eye color=blue, hair color=brown}
keys: height, weight, eye color, hair color,
elements: 6 feet, 200 pounds, blue, brown,
height: 6 feet
weight: 200 pounds
eyes: blue
hair: brown
h: {height=6 feet, eye color=blue, hair color=brown}

The Properties Class

The Properties class is a subclass of Hashtable that can be read from or written to a stream. It also provides the capability to specify a set of default values to be used if a specified key is not found in the table. The default values themselves are specified as an object of class Properties. This allows an object of class Properties to have a default Properties object, which in turn has its own default properties, and so on.

Properties supports two constructors: a default constructor with no parameters, and a constructor that accepts the default properties to be associated with the Properties object being constructed.

The Properties class declares several new access methods. The getProperty() method allows a property to be retrieved using a String object as a key. A second overloaded getProperty() method allows a value string to be used as the default in case the key is not contained in the Properties object.

The load() and save() methods are used to load a Properties object from an input stream and save it to an output stream. The save() method allows an optional header comment to be saved at the beginning of the saved object's position in the output stream.

The propertyNames() method provides an enumeration of all the property keys, and the list() method provides a convenient way to print a Properties object on a PrintStream object.

PropApp

The PropApp program illustrates the use of the Properties class by retrieving the System properties and displaying them to the console (see Listing 11.5). This program is similar to the SystemApp program of Chapter 10, "Writing Console Applications."

LISTING 11.5. THE SOURCE CODE OF THE PropApp PROGRAM.

import java.lang.System;
import java.util.Properties;
public class PropApp {
 public static void main(String args[]){
  Properties sysProp = System.getProperties();
  sysProp.list(System.out);
 }
}

The program uses the getProperties() method of the System class to retrieve the system properties and assign them to the sysProp variable. The system properties are then listed on the console window using the list() method.

The program's output will vary from machine to machine. Its output, when run from my computer, is as follows:

-- listing properties --
java.specification.name=Java Platform API Specification
awt.toolkit=sun.awt.windows.WToolkit
java.version=1.2beta2
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.tmpdir=c:\windows\TEMP\
user.timezone=PST
java.specification.version=1.2beta2
user.home=C:\JDK1.2BETA2\BIN\..
java-vm.name=non-JIT
os.arch=x86
java.awt.fonts=C:\WINDOWS\Fonts
java.vendor.url=http://www.sun.com/
user.region=US
file.encoding.pkg=sun.io
java.home=C:\JDK1.2BETA2\BIN\..
java-vm.specification.vendor=Sun Microsystems Inc.
java-vm.specification.version=1.0
java.class.path=.;C:\JavaWebServer1.0.3\public_html\c...
line.separator=
os.name=Windows 95
java.vendor=Sun Microsystems Inc.
java.library.path=C:\JDK1.2BETA2\BIN;.;C:\WINDOWS;c:\wi...
java-vm.version=1.2beta2
file.encoding=8859_1
java.specification.vendor=Sun Microsystems Inc.
user.name=jaworskij
user.language=en
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
java.class.version=45.3
os.version=4.0
path.separator=;
java-vm.specification.name=Java Virtual Machine Specification
file.separator=\
user.dir=C:\jdk1.2beta2\ju\ch11
java-vm.vendor=Sun Microsystems Inc. 

JDK 1.2 Collections Classes and Interfaces

The Collections API of JDK 1.2 added 10 new interfaces and 13 new classes to those that you studied in the previous section. These additional classes and interfaces provide a powerful API for working with different types of object collections.

The new collections interfaces introduced with JDK 1.2 are as follows:

Figure 11.1 shows the hierarchical relationships between the classes and interfaces of the Collections API.

FIGURE 11.1. The Collections API class and interface hier-archy.

The new collections classes introduced with JDK 1.2 are as follows:

The right half of Figure 11.1 shows the Collections API class hierarchy. The following subsections show how to work with the new Collections classes and interfaces. Four examples are provided that show you how to work with lists, sets, maps, and the conversion capabilities of the Arrays class.

Working with Lists

Lists are collections whose objects are ordered. Because lists are ordered, their elements can be indexed. Lists allow duplicate elements. Most lists allow the null value to be an element.

The ListApp program of Listing 11.6 shows how to create and use lists. This program creates a LinkedList object that is referenced by the list variable. The add() method if used to add the strings "is", "is", "a", and "a" to the LinkedList object. The add() method is then used to add the null value to the list. The addLast() method is used to add "test" as the last element of the list. The addFirst() method is used to add "This" as the first element of the list. The displayList() method is then invoked to display the elements of the list.

The displayList() method displays the following results:

The size of the list is: 7
This
is
is
a
a
null
test

The displayList() method uses the size() method to determine the number of elements in the list. It invokes the listIterator() method to return an object that implements the ListIterator interface. The argument to the listIterator() method is the index of the first element of the list to return in the ListIterator object. In this case, we used 0 so that the whole list would be returned.

The hasNext() method of the ListIterator interface is used to iterate through the list, and the next() method is used to retrieve the next element of the list. Note that the list can contain the null value, and special provisions are made for printing this value.

LISTING 11.6. THE ListApp PROGRAM.

import java.util.*;
public class ListApp {
 public static void main(String args[]){
    LinkedList list = new LinkedList();
    list.add("is");
    list.add("is");
    list.add("a");
    list.add("a");
    list.add(null);
    list.addLast("test");
    list.addFirst("This");
    displayList(list);
 }
 static void displayList(LinkedList list) {
  System.out.println("The size of the list is: "+list.size());
  ListIterator i = list.listIterator(0);
  while(i.hasNext()){
Object o = i.next();
   if(o == null) System.out.println("null");
   else System.out.println(o.toString());
  }
 }
}

Working with Sets

Sets differ from lists in that they are unordered and cannot contain duplicates of the same element. The SetApp program, shown in Listing 11.7, illustrates the use of sets. It performs the same type of processing as ListApp, but it does so using sets instead of lists.

LISTING 11.7. THE SetApp PROGRAM.

import java.util.*;
public class SetApp {
 public static void main(String args[]){
    HashSet set = new HashSet();
    set.add("This");
    set.add("is");
    set.add("is");
    set.add("a");
    set.add("a");
    set.add(null);
    set.add("test");
    displaySet(set);
 }
 static void displaySet(HashSet set) {
  System.out.println("The size of the set is: "+set.size());
  Iterator i = set.iterator();
  while(i.hasNext()){
   Object o = i.next();
   if(o == null) System.out.println("null");
   else System.out.println(o.toString());
  }
 }
}

SetApp begins by creating an HashSet object and assigning it to the set variable. It then adds the same elements to the set as ListApp did to its list. Note that because sets are not ordered, there are no addFirst() and addLast() methods. The displaySet() method is invoked to display the set. It displays the following results:

The size of the set is: 5
This
is
a
null
test

Note that the set did not allow duplicate elements, but did allow the null value as an element. The displaySet() method uses the size() method to determine the number of elements in the set. It uses the iterator() method to create an Iterator object. The Iterator object is used to step through and display the elements of the set.

Working with Maps

Maps differ from lists and sets in that they are ordered collections of key-value pairs. Maps are a generalization of the Dictionary, Hashtable, and Properties classes that you studied earlier in this chapter. The MapApp program of Listing 11.8 uses an object of the TreeMap class to create a sorted list of key-value pairs. The TreeMap class implements a sorted binary tree.

LISTING 11.8. THE MapApp PROGRAM.

import java.util.*;
public class MapApp {
 public static void main(String args[]){
    TreeMap map = new TreeMap();
    map.put("one","1");
    map.put("two","2");
    map.put("three","3");
    map.put("four","4");
    map.put("five","5");
    map.put("six","6");
    displayMap(map);
 }
 static void displayMap(TreeMap map) {
  System.out.println("The size of the map is: "+map.size());
  Collection c = map.entrySet();
  Iterator i = c.iterator();
  while(i.hasNext()){
   Object o = i.next();
   if(o == null) System.out.println("null");
   else System.out.println(o.toString());
  }
 }
}

The MapApp program begins by creating a TreeMap object and assigning it to the map variable. It then adds six key-value pairs to the map. These key-value pairs associate the names of the numbers from 1 through 6 with their values. The displayMap() method is then invoked to display the program's results:

The size of the map is: 6
five=5
four=4
one=1
six=6
three=3
two=2

The displayMap() method uses the size() method to determine the number of elements (key-value pairs) in the map. It invokes the entrySet() method to create a Collection object containing the values of the map. The iterator() method of the Collection object is used to obtain an Iterator object for the collection. The Iterator object is used to step through and display the elements of the collection. You should note that the TreeMap object uses the key to sort its key-value pairs.

Sorting and Converting

The Arrays and Collections classes provide a number of static methods for searching, sorting, and converting arrays and Collection objects. The ConvertApp program of Listing 11.9 provides an example of these capabilities. This program creates an array of names, sorts the array, converts it to a list, and then displays the values of the list.

LISTING 11.9. THE ConvertApp PROGRAM.

import java.util.*;
public class ConvertApp {
 public static void main(String args[]){
  String strings[] = {"Jason","Emily","Lisa","Jamie","Pierre",
   "Stanley","Gloria","Ben","Ken","Lela"};
  Arrays.sort(strings);
  List list = Arrays.asList(strings);
  displayList(list);
 }
 static void displayList(List list) {
  System.out.println("The size of the list is: "+list.size());
  ListIterator i = list.listIterator(0);
  while(i.hasNext()){
   Object o = i.next();
   if(o == null) System.out.println("null");
   else System.out.println(o.toString());
  }
 }
}

ConvertApp begins by creating an array of first names. It then uses the static sort() method of the Arrays class to sort the array. The asList() method of Arrays is invoked to convert the array to a List object. The displayList() method is then invoked to display the list. Its output follows:

The size of the list is: 10
Ben
Emily
Gloria
Jamie
Jason
Ken
Lela
Lisa
Pierre
Stanley

The displayList() method uses the method of the List interface to determine the size of the list and step through the elements of the list.

Date and Calendar-Related Classes

Another major set of classes supported by the java.util package are classes for working with dates and calendars. The original JDK 1.0 provided the Date class to encapsulate date and time as an object. In JDK 1.1, many of the functions of the Date class were deprecated in favor of more international handling of date and time. The Calendar, GregorianCalendar, SimpleTimeZone, and TimeZone classes were added to provide more comprehensive and international support of date and time. The DateFormat class of the java.text package was also added to support international date formatting.


NOTE: A deprecated API element is one that has been replaced by an improved alternative. In most cases, the deprecated element may still be used. However, compiler warnings are generated to inform you that an improved alternative exists.

Date

The Date class encapsulates date and time information and allows date objects to be accessed in a system-independent manner.

Four of the six Date JDK 1.0 constructors have been deprecated. Only the default constructor that creates a Date object with the current system date and time, and a constructor that creates a Date object from a long value, are not deprecated in JDK 1.2.

The access methods defined by the Date class support comparisons between dates and provide access to specific date information, including the time zone offset. However, many of the JDK 1.0 methods have been deprecated in favor of methods provided by the Calendar, DateFormat, and TimeZone classes.

Calendar

The Calendar class provides support for date conversions that were previously implemented by the Date class. The support provided by Calendar is more comprehensive and international. The Calendar class is an abstract class that can be extended to provide conversions for specific calendar systems. The GregorianCalendar subclass supports the predominant calendar system used by many countries.

The Calendar class provides two constructors--a default parameterless constructor that constructs a calendar with the default TimeZone and Locale objects, and a constructor that allows the TimeZone and Locale objects to be specified. It supplies many constants for accessing days of the week, months of the year, hours, minutes, seconds, milliseconds, and other values.

The Calendar class provides a number of methods for performing data comparisons, arithmetic, and conversions. The getInstance() method returns a locale-specific calendar that is a GregorianCalendar object, by default.

GregorianCalendar

The GregorianCalendar class is a subclass of the Calendar class that supports calendar operations for most of the world. It supports the eras B.C. and A.D. by defining them as class constants. It provides seven constructors that allow GregorianCalendar objects to be created using a combination of different date, time, time zone, and locale values. Its methods override those provided by the Calendar class.

TimeZone

The TimeZone class is used to encapsulate the notion of a time zone. It allows you to work in the local time zone, as well as time zones that are selected by a time zone ID. The TimeZone class keeps track of daylight savings time.

The TimeZone class provides a single, parameterless constructor that creates a TimeZone object corresponding to the local time zone. The TimeZone class does not define any field variables.

The access methods of TimeZone allow you to get a list of available time zone IDs, retrieve the local time zone (from the operating system), get the local time zone offset (and adjust it for daylight savings time), and create TimeZone objects for other time zone IDs.

SimpleTimeZone

The SimpleTimeZone class extends TimeZone to provide support for GregorianCalendar objects. It creates SimpleTimeZone objects using the time zone IDs and offsets defined in the TimeZone class. It provides methods for changing the way daylight savings time is calculated.

DateApp

The DateApp program illustrates the use of the date-related classes covered in the previous sections. It shows how Date, GregorianCalendar, and TimeZone objects are created and how to use their methods to access date/time information. The DateApp program is presented in Listing 11.10.

LISTING 11.10. THE SOURCE CODE OF THE DateApp PROGRAM.

import java.lang.System;
import java.util.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class DateApp {
 public static void main(String args[]){
  Date today = new Date();
  GregorianCalendar cal = new GregorianCalendar();
  cal.setTime(today);
  System.out.println("Today: ");
  displayDateInfo(cal);
  cal.clear();
  cal.set(2000,0,1);
  System.out.println("\nNew Years Day 2000: ");
  displayDateInfo(cal);
 }
 static void displayDateInfo(GregorianCalendar cal){
  String days[] = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  String months[] = {"January","February","March","April","May",
   "June","July","August","September","October","November",
   "December"};
  String am_pm[] = {"AM","PM"};
  System.out.println("Year: "+cal.get(Calendar.YEAR));
  System.out.println("Month: "+months[cal.get(Calendar.MONTH)]);
  System.out.println("Date: "+cal.get(Calendar.DATE));
  System.out.println("Day: "+days[cal.get(Calendar.DAY_OF_WEEK)]); 
  System.out.println("Hour: "+(cal.get(Calendar.HOUR)+12)%13);
  System.out.println("Minute: "+cal.get(Calendar.MINUTE));
  System.out.println("Second: "+cal.get(Calendar.SECOND));
  System.out.println(am_pm[cal.get(Calendar.AM_PM)]);
  TimeZone tz=cal.getTimeZone();
  System.out.println("Time Zone: "+tz.getID());
 }
}

The program creates a Date object and a GregorianCalendar object using the default Date() and GregorianCalendar() constructors. The Date object is assigned to the today variable, and the GregorianCalendar object is assigned to the cal variable. The cal variable is updated with the current date by invoking its setTime() method with the Date object stored in today. The displayDateInfo() method is then invoked to display date and time information about the cal variable.

The clear() method of the Calendar class is invoked to reset the date of the GregorianCalendar object stored in cal. The set() method is used to set its date to New Year's 2000. There are several versions of the set() method, each of which takes a different set of parameters. The version used in DateApp takes the year, month, and date as parameters. Note that the month value ranges from 0 to 12, where the year and date values begin at 1. The displayDateInfo() method is invoked again to display information about the new calendar date.

The displayDateInfo() method creates the days, months, and am_pm arrays to define string values corresponding to the days of the week, months of the year, and a.m./p.m. It then prints a line corresponding to date and time values. These values are retrieved using the get() method of the Calendar class and the Calendar constants corresponding to date/time values. The getTimeZone() method of Calendar is invoked to retrieve the local TimeZone object. The getID() method of the TimeZone class is used to retrieve the local time zone ID string.

The output of the DateApp program follows. When you run the program, you will obviously get a different date for the first part of the program's processing. The following are the results that were displayed when I ran the program:

Today:
Year: 1998
Month: July
Date: 28
Day: Tue
Hour: 10
Minute: 57
Second: 6
AM
Time Zone: America/Los Angeles
New Years Day 2000:
Year: 2000
Month: January
Date: 1
Day: Sat

Hour: 12

Minute: 0
Second: 0
AM
Time Zone: America/Los Angeles

Internationalization Classes

The java.util package provides a number of classes that support internationalization. These classes are described in this section. Examples of their use are provided in Chapter 19, "Internationalization."

The Locale Class

The Locale class supports internationalization by describing geographic, political, or cultural regions. Locale objects are used to tailor program output to the conventions of that region. They are created using the Locale() constructors, which take language and country arguments and an optional variant argument. The variant argument is used to specify software-specific characteristics, such as operating system or browser. The Locale class defines constants for the most popular languages and countries. The access methods of Locale support the setting and retrieving of language, country, and variant-related values. Examples of using the Locale class are provided in Chapter 19.

The ResourceBundle Class

The ResourceBundle class also supports internationalization. ResourceBundle subclasses are used to store locale-specific resources that can be loaded by a program to tailor the program's appearance to the particular locale in which it is being run. Resource bundles provide the capability to isolate a program's locale-specific resources in a standard and modular manner.

The ResourceBundle class provides a single parameterless constructor. The parent field variable is used to identify the ResourceBundle class that is the parent of a particular class. This parent can be set using the setParent() method. The parent is used to find resources that are not available in a particular class.

The ResouceBundle access methods are used to retrieve the resources that are specific to a particular locale. The ResourceBundle class and its subclasses are covered in Chapter 19.

The ListResourceBundle Class

The ListResourceBundle class extends the ResourceBundle class to simplify access to locale-specific resources. It organizes resources in terms of an array of object pairs, where the first object is a String key and the second object is the key's value. The getContents() method returns the key-value array.

The PropertyResourceBundle Class

The PropertyResourceBundle class extends the ResourceBundle class to organize locale-specific resources using a property file. An InputStream object is supplied to the PropertyResourceBundle() constructor to enable reading of the property file.

Other java.util Classes and Interfaces

The java.util package provides a number of other classes and interfaces that provide capabilities that can be used in many of your programs. These remaining classes and interfaces are covered in the following subsections.

The Random Class

The Random class provides a template for the creation of random number generators. It differs from the random() method of the java.lang.Math class in that it allows any number of random number generators to be created as separate objects. The Math.random() method provides a static function for the generation of random double values. This static method is shared by all program code.

Objects of the Random class generate random numbers using a linear congruential formula. Two constructors are provided for creating Random objects. The default constructor initializes the seed of the random number generator using the current system time. The other constructor allows the seed to be set to an initial long value.

The Random class provides eight access methods, seven of which are used to generate random values. The next(), nextInt(), nextLong(), nextFloat(), and nextDouble() methods generate values for the numeric data types. The values generated by nextFloat() and nextDouble() are between 0.0 and 1.0. The nextGaussian() method generates a Gaussian distribution of double values with mean 0.0 and standard deviation 1.0. The nextBytes() method generates a random byte array.

The setSeed() method is used to reset the seed of the random number generator.

RandomApp

The RandomApp program demonstrates the use of the Random class (see Listing 11.11). It creates an object of class Random using the default constructor and assigns it to r. This causes the random number generator to be seeded using the current system time. Three for loops are used to print random int, double, and Gaussian-distributed double values. Each loop prints four values.

LISTING 11.11. THE SOURCE CODE OF THE RandomApp PROGRAM.

import java.lang.System;
import java.util.Random;
public class RandomApp {
 public static void main(String args[]){
  Random r = new Random();
  for(int i=0;i<4;++i) System.out.print(r.nextInt()+" ");
  System.out.println();
  r = new Random(123456789);
  for(int i=0;i<4;++i) System.out.print(r.nextDouble()+" ");
  System.out.println();
  r.setSeed(234567890);
  for(int i=0;i<4;++i) System.out.print(r.nextGaussian()+" ");
  System.out.println();
 }
}

The following is the output generated by the program when it was run on my computer:

-854287801 -2056322098 1372478715 1217144804
0.664038103272266 0.45695178590520646 0.39050647939140426 0.8933411602003871
0.11378145160284903 0.4122962630933344 -1.5726230841498485 0.07568285309772235

It will produce different results when it is run on your computer because the first line that is printed uses the Random() constructor to generate the output data.

The StringTokenizer Class

The StringTokenizer class is used to create a parser for String objects. It parses strings according to a set of delimiter characters. It implements the Enumeration interface in order to provide access to the tokens contained within a string. The StringTokenizer class is similar to the StreamTokenizer class covered in Chapter 17, "Input/Output Streams."

StringTokenizer provides three constructors. All three have the input string as a parameter. The first constructor includes two other parameters: a set of delimiters to be used in the string parsing, and a boolean value used to specify whether the delimiter characters should be returned as tokens. The second constructor accepts the delimiter string, but not the return token's toggle. The last constructor uses the default delimiter set consisting of the space, tab, newline, and carriage-return characters.

The access methods provided by StringTokenizer include the Enumeration methods, hasMoreElements() and nextElement(), hasMoreTokens() and nextToken(), and countTokens(). The countTokens() method returns the number of tokens in the string being parsed.

TokenApp

The TokenApp program prompts the user to enter a line of keyboard input and then parses the line, identifying the number and value of the tokens that it found (see Listing 11.12).

LISTING 11.12. THE SOURCE CODE OF THE TokenApp PROGRAM.

import java.lang.System;
import java.io.*;
import java.util.StringTokenizer;
public class TokenApp {
 public static void main(String args[]) throws IOException {
  BufferedReader keyboardInput = new BufferedReader(
   new InputStreamReader(System.in));
  int numTokens;
  do {
   System.out.print("=> ");
   System.out.flush();
   StringTokenizer st = new StringTokenizer(keyboardInput.readLine());
   numTokens = st.countTokens();
   System.out.println(numTokens+" tokens");
   while (st.hasMoreTokens())
    System.out.println(" "+st.nextToken());
  } while(numTokens!=0);
 }
}

The program begins by creating a BufferedReader object using the System.in stream as an argument to its constructor. A do loop is used to read a line of input from the user, construct a StringTokenizer object on the input line, display the number of tokens in the line, and display each token as parsed using the standard delimiter set. The loop continues until a line with no tokens is entered.

The program's output is as follows:

=> this is a test
4 tokens
 this
 is
 a
 test
=> 1 2 3 4.5 6
5 tokens
 1
 2
 3
 4.5
 6
=> @ # $ % ^
5 tokens
 @
 #
 $
 %
 ^
=>
0 tokens

Observer and Observable

The Observer interface and Observable class are used to implement an abstract system by which observable objects can be observed by objects that implement the Observer interface. Observable objects are objects that subclass the abstract Observable class. These objects maintain a list of observers. When an observable object is updated, it invokes the update() method of its observers to notify the observers that it has changed state.

The update() method is the only method that is specified in the Observer interface. The update() method is used to notify an observer that an Observable object has changed. The method takes the Observable object and a second notification message Object as its parameters.

The Observable class is an abstract class that must be subclassed by Observable objects. It provides several methods for adding, deleting, and notifying observers and for manipulating change status. These methods are described in the class's API page.

The EventObject Class and the EventListener Interface

The EventObject class is the top-level class of the Java event hierarchy. Events represent actions that occur during the course of program execution. Most events are generated as the result of user actions, such as mouse clicks and keyboard actions. The java.awt.event package declares event classes that are subclasses of EventObject. The EventObject class contains a single constructor that identifies the object that is the source of the event. This object is accessible through the source field variable. The EventObject class also provides the getSource() method for accessing the event source.

Events are handled by responding to their occurrence and providing feedback to the user. Java 1.1 provided the capability to deliver events to specific objects--a capability that was lacking in Java 1.0.

It makes use of special classes, called adapter classes, whose objects listen for the occurrence of events on behalf of objects of other classes. These classes implement event listener interfaces that specify methods for identifying and responding to the occurrence of related events. The EventListener interface is the top-level interface that all listener interfaces must implement. It is an empty interface and does not declare any methods.

The PropertyPermission Class

The PropertyPermission class is used to create permissions to access specific system properties. You should not use this class yourself. Instead, specify property permissions in your local security policy. Chapter 3, "The Extended Java Security Model," covers the development of a JDK 1.2 security policy.

The java.util.zip Package

The java.util.zip package provides 1 interface and 14 classes to support the compression and decompression of files and streams and to support checksum calculation. These classes are described in the following sections.

Checksum

The Checksum interface provides four methods that support checksum calculation. The getValue() method returns the current value of a checksum. The reset() method resets a checksum to its initial value. The two update() methods update a checksum based on a single byte or an array of bytes.

Adler32

The Adler32 class implements the Checksum interface to compute an Adler-32 checksum. The Adler-32 checksum is computed quickly, but is less reliable than the CRC32 checksum.

CRC32

The CRC32 class implements the Checksum interface to calculate a standard 32-bit cyclic redundancy code.

CheckedInputStream

The CheckedInputStream class extends the FilterInputStream class of java.io to include a checksum calculation for data read from the stream. The checksum is used to verify the integrity of the stream's data. The CheckedInputStream() constructor creates a CheckedInputStream object from an InputStream object and an object that implements the Checksum interface. The getChecksum() method returns the Checksum object associated with the stream. Other methods support low-level input.

CheckedOutputStream

The CheckedOutputStream class extends the FilterOutputStream class of java.io to include a checksum calculation for data written to the stream. The checksum is used to verify the integrity of the stream's data. The CheckedOutputStream() constructor creates a CheckedOutputStream object from an OutputStream object and an object that implements the Checksum interface. The getChecksum() method returns the Checksum object associated with the stream. Other methods support low-level output.

Deflater

The Deflater class supports compression using the compression approaches described in Request For Comments (RFCs) 1950, 1951, and 1952. RFCs are publicly available Internet standards that can be found at ftp://ds.internic.net/rfc/. The Deflater class supports the following compression levels and strategies, as defined by its field constants:

The compression level can be selected when constructing a Deflater object.

The methods of the Deflater class support data compression, the selection of a compression level and strategy, and the use of preset data dictionaries. These methods perform block-oriented compression on byte arrays.

Inflater

The Inflater class is used to decompress data that is compressed by the Deflater class. This decompression is also covered in RFCs 1950, 1951, and 1952. The Inflater() constructor provides the nowrap parameter to support GZIP- and PKZIP-compatible compression. GZIP compression is the Gnu public version of the commercial PKZIP compression algorithm developed by Phil Katz.

The methods of the Inflater class support decompression and the use of preset data dictionaries. These methods perform block-oriented decompression on byte arrays.

DeflaterOutputStream

The DeflaterOutputStream class extends the FilterOutputStream class to provide support for stream-oriented compression. Its two field variables, buf and def, identify the output buffer used to write compressed data and the type of compressor in use. The DeflaterOutputStream() constructors allow the OutputStream and Deflater objects to be specified, as well as the output buffer size.

The deflate() method writes the next block of compressed data to the output stream. The finish() method completes the compression of the output stream by writing all compressed data to the stream. Other methods support low-level data output.

InflaterInputStream

The InflaterInputStream class is the input analog of the DeflaterOutputStream class. InflaterInputStream reads and decompresses data that is written to a compressed output stream using a DeflaterOutputStream object. It extends the FilterInputStream class of java.io.

InflaterInputStream defines three field variables: buf, inf, and len. These variables identify the input buffer used for decompression, the type of decompressor to be used, and the length of the input buffer. The InflaterInputStream() constructors allow InputStream and Inflater objects to be specified, as well as the input buffer size.

The fill() method is used to fill the input buffer with compressed data. Other methods are used to read uncompressed data from the stream.

GZIPOutputStream

The GZIPOutputStream class extends DeflaterOutputStream to support GZIP compression. It adds the crc field variable to calculate a CRC-32 checksum on the compressed data. The GZIPOutputStream() constructors allow the OutputStream object and the output buffer size to be specified.

GZIPInputStream

The GZIPInputStream class is the input analog of the GZIPOutputStream class. It extends InflaterInputStream and defines two additional variables and a constant. The crc variable identifies the CRC-32 checksum of the compressed data. The eos variable identifies the end of the output stream. The GZIP_MAGIC constant identifies the magic number of the GZIP header. Magic numbers are used to uniquely identify files of a given format. The GZIPInputStream() constructors allow the InputStream object and the input buffer size to be specified.

ZipFile

The ZipFile class is used to read .zip compressed files. The ZipFile() constructor opens a ZIP file for reading. A File object or a String object containing a file name may be provided to the ZipFile() constructor.

The methods of the ZipFile class support the reading and examination of .zip files. They are as follows:

ZipEntry

The ZipEntry class encapsulates a .zip file entry. It represents a compressed file that is stored within the .zip file. The DEFLATED and STORED constants are used to identify whether a .zip entry is compressed or merely stored as uncompressed data within the .zip file. The ZipEntry() constructor is used to create a named .zip file entry. Several methods are provided to read the following aspects of a ZipEntry object:

Other methods are provided to set the comment string, CRC, extra field data, entry size, and time of modification. The toString() method is overridden to convert a ZipEntry object to a String object.

ZipOutputStream

The ZipOutputStream class extends the DeflaterOutputStream class to support the writing of file streams that are compressed in the .zip file format. The DEFLATED and STORED constants are used to identify whether data should be compressed (DEFLATED) or stored as uncompressed data (STORED). The ZipOutputStream() constructor creates a ZipOutputStream object from an OutputStream object.

In addition to low-level output methods, the ZipOutputStream class provides the following methods:

ZipInputStream

The ZipInputStream class is the input analog to the ZipOutputStream class. It is used to read a compressed .zip format file. The ZipInputStream class extends the InflaterInputStream class.

The ZipInputStream() constructor creates a ZipInputStream object from an InputStream object. In addition to low-level input methods, it provides the getNextEntry() method for reading the next .zip file entry and the closeEntry() method for closing a .zip file entry.

The UnzipApp Program

The UnzipApp program, shown in Listing 11.13, illustrates the power of the java.util.zip in working with compressed files. This short program can be used to unzip files in the .zip format.

LISTING 11.13. THE SOURCE CODE OF THE UnzipApp PROGRAM.

import java.lang.System;
import java.util.*;
import java.util.zip.*;
import java.io.*;
public class UnzipApp {
 public static void main(String args[]) throws IOException {
  if(args.length==0) System.exit(0);
  ZipFile f = new ZipFile(args[0]);
  Enumeration entries = f.entries();
  System.out.println("Decompressing "+args[0]+" ...");
  while(entries.hasMoreElements()){
   ZipEntry entry = (ZipEntry) entries.nextElement();
   System.out.println("  "+entry.getName());
   InputStream in = f.getInputStream(entry);
   FileOutputStream out = new FileOutputStream(entry.getName());
   for(int ch=in.read();ch!=-1;ch=in.read()) out.write(ch);
   out.close();
   in.close();
  }
  f.close();
 }
}

To show how the program works, I've included the file rfcs.zip on the CD-ROM included with this book. This file contains the files rfc1950.txt, rfc1951.txt, and rfc1952.txt in compressed form. These files document the conventions and formats used for ZLIB, DEFLATE, and GZIP.

The UnzipApp program takes a single argument--the name of the file that you want to unzip. To unzip rfcs.zip, use:

java UnzipApp rfcs.zip

The program's output is as follows:

Decompressing rfcs.zip ...
  rfc1950.txt
  rfc1952.txt

rfc1951.txt

The files rfc1950.txt, rfc1951.txt, and rfc1952.txt are created and placed in your current working directory.

The program makes use of the ZipFile and ZipEntry classes of java.util.zip and the Enumeration interface of java.util. It creates a new ZipFile object from the filename that you pass to the program as a command-line argument. It then invokes the entries() method of ZipFile to create an Enumeration object of ZipEntry objects corresponding to the entries into the ZipFile object.

A while statement is used to loop through the Enumeration object and process each entry. The hasMoreElements() method of the Enumeration interface is used to determine whether all entries have been processed. The individual ZipEntry objects are extracted from the Enumeration object via the nextElement() method and assigned to the entry variable. The getName() method of the ZipEntry class is used to retrieve the filename associated with each ZipEntry object.

The ZipEntry objects are extracted to individual files by using the getInputStream() method of ZipFile to read the contents of the ZipEntry object and write this data to files that are created using the FileOutputStream class of java.io.

The java.util.jar Package

The java.util.jar package provides classes and methods for working with .jar files. The .jar files are archive files used to combine all of the resources used by an applet into a single file. You learned about .jar files in Chapter 8, "Applet Security." The java.util.jar package is new to JDK 1.2. It provides seven new classes that are covered in the following subsections.

The JarFile Class

The JarFile class extends the ZipFile class to provide support for .jar files. It provides the capability to add and work with the .jar file manifest. The JarFile constructors are used to create JarFile objects that take their input from an input stream. The getManifest() method returns the file's manifest. The getJarEntry() returns a named .jar file entry as an JarEntry object. The createZipEntry() method is used to create a JarEntry object. The getInputStream() method returns an input stream for reading the .jar file.

The JarEntry Class

The JarEntry class extends the ZipEntry class to provide support for .jar file entries. It provides a single constructor for creating a named .jar file entry. The getAttributes() method returns an Attributes object that specifies the manifest attributes for the entry. The getIdentities() method returns an array of Identity objects that identifies the identities of the signers of the .jar file entry.

The Manifest Class

The Manifest class provides the capability to work with manifest entries and their attributes. It provides methods for reading and manipulating manifest entries, main attributes, and per-entry attributes.

The Attributes Class

The Attributes class implements the Map interface and provides a mapping between attribute names and their values. It provides methods for reading and modifying the attribute names and values.

The Attributes.Name Class

The Attributes.Name class is an inner class of the Attributes class that is used to encapsulate an attribute name. It provides a number of constants that represent commonly used manifest attributes.

The JarInputStream Class

The JarInputStream class is a subclass of the ZipInputStream class that supports the reading of .jar files. It provides methods for reading JarEntry and Manifest objects.

The JarOutputStream Class

The JarOutputStream class is a subclass of the ZipOutputStream class that supports the writing of .jar files. It provides the capability to specify a Manifest object in one of its constructors.

The JarApp Program

The JarApp program illustrates the use of the JarFile, JarEntry, Manifest, and Attributes classes. It reads a .jar file and displays the JAR entries, main attributes, and manifest entries of the .jar file.

I've added the file TCanv.jar to the files contained on the CD-ROM for this chapter. You can use JarApp to display the contents of the TCanv.jar file, as follows:

java JarApp TCanv.jar
Entries:
  tcanv16m.gif
  TCanvBeanInfo.class
  tcanv32c.gif
  META-INF/MANIFEST.MF
  TCanv.class
  tcanv32m.gif
  tcanv16c.gif
Main attributes:
  Manifest-Version 1.0
Manifest entries:
  tcanv16m.gif java.util.jar.Attributes@df93530
  TCanvBeanInfo.class java.util.jar.Attributes@57e4cd07
  TCanv.class java.util.jar.Attributes@c88bc2f1
  tcanv32c.gif java.util.jar.Attributes@9381af57
  tcanv16c.gif java.util.jar.Attributes@272d3530
  tcanv32m.gif java.util.jar.Attributes@8de1af57

JarApp begins by creating a JarFile object from the name of the .jar file passed as an argument to the program. It uses the entries() method to retrieve an Enumeration of the JarEntry objects contained in the .jar file. It invokes getManifest() to retrieve a Manifest object for the .jar file.

The JarApp program iterates through the Enumeration of JarEntry objects and uses the getName() method to display the names of the files that are contained in TCanv.jar:

  tcanv16m.gif
  TCanvBeanInfo.class
  tcanv32c.gif
  META-INF/MANIFEST.MF
  TCanv.class
  tcanv32m.gif
  tcanv16c.gif

It invokes the getMainAttributes() method of the Manifest object to retrieve an Attributes object that describes the main attributes of the .jar file. It invokes displayCollection() to display the single attribute (Manifest-Version) and its value (1.0).

Next, JarApp invokes the getEntries() method of the Manifest object to return a Map object containing the manifest entries and their values. It invokes displayCollection() to display these values:

  tcanv16m.gif java.util.jar.Attributes@df93530
  TCanvBeanInfo.class java.util.jar.Attributes@57e4cd07
  TCanv.class java.util.jar.Attributes@c88bc2f1
  tcanv32c.gif java.util.jar.Attributes@9381af57
  tcanv16c.gif java.util.jar.Attributes@272d3530
  tcanv32m.gif java.util.jar.Attributes@8de1af57

The displayCollection() method displays a collection of key-value pairs. It invokes the iterator() method of the Collection object to obtain an Iterator object. It then uses the Iterator object to step through the collection and display each key name and its corresponding value.

LISTING 11.14. THE JarApp PROGRAM.

import java.util.*;
import java.util.jar.*;
import java.io.*;
public class JarApp {
 public static void main(String args[]) throws IOException {
  // Create JarFile object
  JarFile f = new JarFile(args[0]);
  // Get JarEntry objects
  Enumeration entries = f.entries();
  // Get Manifest
  Manifest manifest = f.getManifest();
  // Display the names of the entries
  System.out.println("Entries:");
  while(entries.hasMoreElements()){
   JarEntry entry = (JarEntry) entries.nextElement();
   System.out.println("  "+entry.getName());
  }
  // Display the names of the main attributes
  System.out.println("Main attributes:");
  Attributes attributes = manifest.getMainAttributes();
  displayCollection(attributes.entrySet());
  // Display the manifest entries and their attributes
  System.out.println("Manifest entries:");
  Map manifestEntries = manifest.getEntries();
  displayCollection(manifestEntries.entrySet());  
  f.close();
 }
 static void displayCollection(Collection collection) {
  if(collection.size()==0) System.out.println("  None");
  else{
   Iterator iterator = collection.iterator();
   while(iterator.hasNext()){ 
    Map.Entry entry = (Map.Entry) iterator.next();
    String desc = entry.getKey().toString()+" ";
    desc+=entry.getValue().toString();
    System.out.println("  "+desc);
   }
  }
 }
}

The java.util.mime Package

The java.util.mime package is new to JDK 1.2. It is a very small package consisting of the MimeType and MimeTypeParameterList classes. These classes are used to provide support for Multipurpose Internet Mail Extensions (MIME) types (refer to RFCs 2045 and 2046). Chapter 33, "Content and Protocol Handlers," provides an introduction to MIME types.

The MimeType class provides methods for constructing MimeType objects that represent different MIME types, for accessing the primary and subtypes of a MIME type, for working with MIME type parameters, and for comparing MIME types. It also provides methods for supporting stream-based I/O for different MIME types.

The MimeTypeParameterList class is used to encapsulate the parameter list of a MIME type. It provides methods for getting and setting the parameters that are in the MIME type parameter list.

The java.math Package

The java.math package includes two classes, BigDecimal and BigNumber, that can be used to perform arbitrary precision mathematical calculations. The BigDecimal class supports decimal arithmetic, and the BigInteger class supports integer arithmetic. Both of these classes extend the Number class.

BigDecimal

The BigDecimal class is implemented as an arbitrary precision integer number and a non-negative scale value that identifies the number of digits to the right of the decimal point. BigDecimal provides eight modes for rounding support. These modes are defined using class constants:

These modes provide a great deal of flexibility in the rounding policy used by the BigDecimal class.

The BigDecimal class provides constructors that allow BigDecimal objects to be created from String, double, and BigInteger objects. The methods of BigDecimal support arithmetic operations, comparisons, rounding and scaling, and conversions to other types and classes.

BigInteger

The BigInteger class is similar to BigDecimal, but it is limited to integer operations. It does not have any public field values, like BigDecimal, because it does not deal with rounding. Its constructors allow BigInteger objects to be constructed from strings, byte arrays, and randomly within a specified range. Its methods support arithmetic, logical, bitwise, and comparison operations. Its methods also support modular arithmetic, greatest common divisor calculation, and prime number generation and testing.

The BigNumApp Program

The BigNumApp program illustrates the ease by which large number computations can be performed. It calculates the first number greater than a trillion (10 to the 12 power) that is probably prime. Listing 11.15 contains the source code of the BigNumApp program.

LISTING 11.15. THE SOURCE CODE OF THE BigNumApp PROGRAM.

import java.lang.System;
import java.math.BigInteger;
public class BigNumApp {
 public static void main(String args[]){
  BigInteger n=new BigInteger("1000000000000");
  BigInteger one=new BigInteger("1");
  while(!n.isProbablePrime(7)) n=n.add(one);
  System.out.println(n.toString(10)+" is probably prime.");
  System.out.println("It is "+n.bitLength()+" bits in length.");
 }
}

The BigNumApp program creates a BigInteger equal to one trillion and assigns it to n. It then creates a BigInteger equal to 1 and assigns it to the one variable. It uses a while loop to test numbers greater than a trillion until it finds one that is probably prime with a certainty of 7. This certainty value means that the probability of the number being prime is (1 - (1/2**7)), which is greater than 99%. The bitLength() method is to determine the length of the prime number in bits.

The program's output is as follows:

1000000000039 is probably prime.
It is 40 bits in length.

Summary

In this chapter you learned about the classes and interfaces of the java.util family of packages and the java.math package. You learned how to use the new JDK 1.2 Collections API, work with dates and calendars, work with .zip and .jar files, and perform large number arithmetic. In the next chapter you'll learn how to use the new Java Swing API to enhance the look and feel of your applets' and applications' user interfaces.


Contents

© Copyright, Macmillan Computer Publishing. All rights reserved.