Going Pro #2

Creating and Using Our Own Packages


CS 2530
Intermediate Computing


Introduction

A package is a group of related classes and interfaces. A big part of what we call Java is actually the extensive set of packages that accompany the syntax and language primitives. Java programmers can extend the language in this same way, by defining useful groups of classes and interfaces and providing them as packages.

There are several good reasons to create packages. Some are about communication. Grouping classes and interfaces together in a package is a way to tell other programmers that they are related. It also helps programmers find the classes and interfaces related to what they want to do.

Some of the reasons are about writing programs. A package creates a separate namespace. It allows us to have and use classes that have the same name, by having the classes reside in different packages. In Java, members of a package can be given access to one another that is not available to other classes. This means that a package creator can grant unrestricted access to one set of classes while providing limited access to classes outside the package. (To me, this often feels like friend status in a C++ program.)

The names of Java's built-in packages are all of the form java.package, such as java.io and java.util. Java also nests some packages inside other others, such as java.awt and java.awt.event.

User-created packages can have single-word names. In the case of our strategies for testing words in documents, we might name our package wordfeature.

A common convention for naming multiple packages from the same source or installation is to use the domain name of the creator. For instance, I might make a package named edu.uni.cs.wallingf to contain all of the code I use, or edu.uni.cs.wallingf.cs2530 for all the code we use in Intermediate Computing. Package names qualified in this name indicate that the packages are nested as subdirectories, like Java's.



Creating a Package

Let's demonstrate the process of creating and using packages by packaging up all the files for our word feature strategies in a package named wordfeature.

  1. Put all the files in directory named wordfeature.

    This includes the WordFeature interface, the concrete strategies StartsWith, OfLength, and IsAPalindrome, and the composite CompoundFeature.


  2. Add the package directive to the top of each file.

    This must be top non-comment line of the file. For example, WordFeature.java becomes

             package wordfeature;
    
             public interface WordFeature
             {
               public boolean hasFeature( String s );
             }
    

That's all there is to creating the package. Now let's use it.



Using the Package

The simplest way to use a package of this sort is to place its directory in the same directory with the code that uses it. Suppose that my working directory contains our wordfeature package:

    > ls -al
    ...
    -rw-r--r--  1 wallingf  staff    1710 Dec  7 14:32 Play.java
    -rw-r--r--  1 wallingf  staff     811 Dec  7 14:28 WordLengths.java
    -rw-r--r--  1 wallingf  staff  191734 Dec  7 14:30 hamlet.txt
    drwxr-xr-x  8 wallingf  staff     272 Dec  7 14:37 wordfeature

There are two ways to refer to members of the package in our programs. One way is to import all the members. For example, I added a new import directive at the top of WordLengths.java:

    import java.io.IOException;
    import wordfeature.*;
This is a common way to import a large number of classes and interfaces at once, say, from the java.awt packages.

Another way is to import individual members. For example, I added several new import directives at the top of Play.java:

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.StringTokenizer;
    import java.util.Vector;
    import wordfeature.WordFeature;
    import wordfeature.StartsWith;
    import wordfeature.OfLength;
I like to import members individually whenever I would like readers (including me!) to be able tell which classes and interfaces are being used in the class. I often do this in Intermediate Computing.

Finally, you may refer to a package member without importing it if you use its full-qualified name. For example, in Play.java, I used the IsAPalindrome class without importing it:

    public int numberOfPalindromes()
    {
      return countWords( new wordfeature.IsAPalindrome() );
    }
I don't know how often this is done in industry, or when. I rarely do this.

Now we compile Play.java and WordLengths.java and run them as usual:

    > javac WordLengths.java
    > java WordLengths hamlet.txt 10 p
    The document in the file hamlet.txt contains ...
         0 words of 1 characters
         1 words of 2 characters
         123 words of 3 characters
         206 words of 4 characters
         118 words of 5 characters
         131 words of 6 characters
         169 words of 7 characters
         128 words of 8 characters
         40 words of 9 characters
         31 words of 10 characters
      ... that start with 'p'.

Dandy!

If you want to use a package in many programs from multiple directories, you won't want to copy the directory into all those locations. Instead, put it into a common location with your other packages and make sure the path to the package is on your Java classpath.



Eugene Wallingford ..... wallingf@cs.uni.edu ..... December 7, 2012