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.
|