Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Technical Tips

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
Print Button
 
Tech Tips index

Tech Tips
April 21, 1998

This issue presents tips, techniques, and sample code for the following topics:

Using Java Collections.
The Collection interface is a new feature of JDKTM 1.2. A "collection" in data structure terms is a group of elements. Some types of collections that derive from Collection include the following:

  • List -- an interface specifying an ordered sequence of elements
  • Set -- an interface specifying a mathematical set of elements, with no duplication
  • Vector -- an implementation of List

Specifying interfaces in this way lets you manipulate collections without having to know the details of how a given collection is implemented. Note that existing data types like Vector have been incorporated into the Collection framework.

To see why the collections approach can be useful, consider a simple example, that of sorting a vector of elements. JDK 1.1 and earlier versions offered no standard way to do this kind of sorting, but collections provides the capability. Consider the following example:


import java.util.*;
   
class Comparer implements Comparator {
  public int compare(Object obj1, Object obj2)
  {
    int i1 = ((Integer)obj1).intValue();
    int i2 = ((Integer)obj2).intValue();
   
    return Math.abs(i1) - Math.abs(i2);
  }
}
  
public class collect {
  public static void main(String args[])
  {
    Vector vec = new Vector();
   
    vec.addElement(new Integer(-200));
    vec.addElement(new Integer(100));
    vec.addElement(new Integer(400));
    vec.addElement(new Integer(-300));
   
    Collections.sort(vec);
    for (int i = 0; i < vec.size(); i++) {
      int e=((Integer)vec.elementAt(i)).intValue();
      System.out.println(e);
    }
   
    Collections.sort(vec, new Comparer());
    for (int i = 0; i < vec.size(); i++) {
      int e=((Integer)vec.elementAt(i)).intValue();
      System.out.println(e);
    }
  }
}

In this example, there is a vector of Integer wrappers on integral quantities. Calling Collections.sort on this vector sorts the vector in a natural way, that is, from lowest to highest according to the values contained in the wrappers. This sorting is achieved by virtue of the fact that all the wrapper types, along with String and a few others, implement an interface called java.lang.Comparable that imposes an ordering on individual elements. And Vector is an implementation of List, which defines a sorting method on lists.

But suppose you want to sort this vector according to your own ordering, one that compares elements according to their absolute magnitude. How can you do this?

One approach is to call Collections.sort again, this time specifying your own ordering. This ordering is done by defining a class "Comparer" that implements the java.util.Comparator interface, returning < 0, 0, or > 0 according to whether the first element is less than, equal to, or greater than the second. The difference between java.lang.Comparable and java.util.Comparator is simply that Comparable is used for types (such as Integer and String) that are built in to the core API, while Comparator is used in cases where you want to specify your own custom element ordering.

Also, there are other features in collections worth investigating, such as the Map interface that replaces Dictionary and binary searches on ordered lists. The benefit of the collection framework is that it provides easier and more powerful use of Java language data structures.

Unpacking Zip Files.
Zip files are used widely for packaging and distributing software. ZipFile is a handy tool for doing the following: reading the contents of .zip and .jar files, obtaining a list of the files they contain, and reading the contents of individual files. Jar files, used in Java software distribution, employ the Zip file format as well. For more information on Jar files, see Tech Tips for September 3, 1997.

java.util.ZipFile is a class used to represent a Zip file. You construct a ZipFile object, and then iterate over the entries in the file, each of which is a ZipEntry. Entries can be checked to determine if they are directories and read from as if they were individual files, in addition to other functions. The ZipFile class is found in both JDK 1.1 and JDK 1.2 beta2.

Here is an example of using ZipFile to dump out the entries and contents of a .zip file. The program accepts a single file argument, along with an optional -contents flag that indicates the contents should also be displayed (note that printing a binary file to screen does not work well).


import java.io.*;
import java.util.Enumeration;
import java.util.zip.*;
   
public class zipview {
  public static void dump(ZipFile zf, ZipEntry ze)
    throws IOException
  {
    System.out.println(">>>>> " + ze.getName());
    InputStream istr = zf.getInputStream(ze);
    BufferedInputStream bis =
      new BufferedInputStream(istr);
    FileDescriptor out = FileDescriptor.out;
    FileOutputStream fos = new FileOutputStream(out);
    int sz = (int)ze.getSize();
    final int N = 1024;
    byte buf[] = new byte[N];
    int ln = 0;
    while (sz > 0 &&  // workaround for bug
      (ln = bis.read(buf, 0, Math.min(N, sz))) != -1) {
        fos.write(buf, 0, ln);
        sz -= ln;
     }
     bis.close();
     fos.flush();
   }
   
   public static void main(String args[])
   {
     boolean dump_contents = false;
     int arg_indx = 0;
     ZipFile zf = null;
   
     if (args.length >= 1 && 
         args[0].equals("-contents")) {
       dump_contents = true;
       arg_indx++;
     }
     if (arg_indx >= args.length) {
       System.err.println("usage: [-contents] file");
       System.exit(1);
     }
   
     try {
       zf = new ZipFile(args[arg_indx]);
     }
     catch (ZipException e1) {
       System.err.println("exception: " + e1);
     }
     catch (IOException e2) {
       System.err.println("exception: " + e2);
     }
   
     Enumeration list = zf.entries();
     while (list.hasMoreElements()) {
       ZipEntry ze = (ZipEntry)list.nextElement();
       if (!dump_contents || ze.isDirectory()) {
         System.out.println(ze.getName());
         continue;
      }
      try {
        dump(zf, ze);
      }
      catch (IOException e) {
        System.err.println("exception: " + e);
      }
    }
  }
} 

This program includes a workaround for a bug in JDK versions 1.1 and 1.2 beta 2, that is, bug #4040920 in the JDC Bug Parade database. Normally, when you read from a low-level file input stream, you read chunks of, say, 1024 bytes at a time, and you don't worry whether that many bytes are actually left to read. This approach fails with the input stream returned by getInputStream for a given Zip file entry, and the workaround is to never try to read more bytes from the entry than are actually there.


Print Button
[ This page was updated: 21-Sep-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary | Feedback | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.