3. Packages Lesson

Java Packages

Java Packages

To see sample solutions, toggle "Show Solutions" above.

Sample solutions not included, because "Show Solutions" was not toggled before printing.

Lesson Objectives

This lesson is designed to provide further practice with command-line text editors as well as compiling Java code organized into packages on a Unix system.

Course-Specific Learning Outcomes

  • LO1.a: Navigate and modify files, directories, and permissions in a multi-user Unix-like environment.

  • LO1.c: Create and modify text files and source code using a powerful terminal-based text editor such as Emacs or Vi.

  • LO1.d: (Partial) Use shell commands to compile new and existing software solutions that are organized into multi-level packages and have external dependencies.

Note

Solutions to the coding parts of this lesson are provided if you toggle "Show Solutions" above. Students are encouraged to review the text/videos in the Packages Chapter for instructions on how to properly create packages directories and details on compilation commands.

Part 1: Compiling to Default Package
Download Starter Code
  1. Use the following command to download the starter code for this activity and place it into a subdirectory named cs1302-hello:

    bundle1302 hello
    
    - downloading cs1302-hello bundle...
    - verifying integrity of downloaded files using sha256sum...
    - extracting downloaded archive...
    - removing intermediate files...
    subdirectory cs1302-hello successfully created
    
Compile Hello.java to Default Package
  1. Navigate to the src directory.

  2. From src, compile Hello.java Don't use the -d option for javac in this step.

  3. Write on exit ticket: What command did you run? What happened when you executed that command? Be as detailed as possible.

Run Hello from src directory
  1. Verify you are still in the src directory.

  2. From src, execute the program.

  3. Write on exit ticket: What command did you run? What happened when you executed that command? Be as detailed as possible.

Remove a file when Outside its Directory
  1. Navigate to the cs1302-hello directory.

  2. Execute the tree command from inside of cs1302-hello directory. You should see output similar to this:

    tree
    
    .
    `-- src
        |-- Hello.class
        `-- Hello.java
    
    Pro Tip

    Unless it is specifically stated, it is best to always work from the main project directory. For example, while working on the source code for this exercise, you can modify all of the files without leaving the cs1302-hello directory by providing the relative path (using tab completion) to the file from the cs1302-hello directory. This means you would rarely use the cd command while working on an assignment. When Unix beginners overuse the cd command, they often find themselves lost in the directory structure which can lead to mistakes and, in rare cases, frustration.

  3. Write on exit ticket: From cs1302-hello, what is the command to delete the compiled (.class) file from src.

Getting Organized
  1. For better organization, let's separate the source code from the compiled code. Directly inside the cs1302-hello directory, add a subdirectory called bin.

  2. From within cs1302-hello, execute a single command to compile Hello.java and place the compiled code into the bin directory? When typing the command, remember to use tab completion. Do not use the cd command.

  3. Tricky: In your groups: try to execute the Hello program from cs1302-hello. Write the command you used in your notes.

  4. Execute the tree command from directly within your cs1302-hello directory. If the previous steps were executed correctly, you should see the following output:

    tree
    
    .
    |-- bin
    |   `-- Hello.class
    `-- src
        `-- Hello.java
    

    Note: If you see any tilde (~) files, those are just backup copies of older versions of your files. You can ignore those.

  5. Write on exit ticket: What command did your group run to compile Hello.java and place the compiled code into the bin directory without using the cd command?

Part 2: Test Yourself

Start in your home directory. Verify the files are organized like this:

cd
tree
.
`-- cs1302-hello
    |-- bin
    |   `-- Hello.class
    `-- src
        `-- Hello.java
Run from your Home Directory

Write on exit ticket: From your home directory (not cs1302-hello), what is the single command to run the Hello program?

Solution
java -cp cs1302-hello/bin Hello
Delete from your Home Directory

Write on exit ticket: From your home directory, what is the command to delete the Hello.class file from the bin folder?

Solution
rm cs1302-hello/bin/Hello.class
tree
.
`-- cs1302-hello
    |-- bin
    `-- src
        `-- Hello.java
tree cs1302-hello
cs1302-hello
|-- bin
`-- src
    `-- Hello.java
cd cs1302-hello
tree
.
|-- bin
`-- src
    `-- Hello.java
Prepare for Part 3
Starter Code
bundle1302 hello
- downloading cs1302-hello bundle...
- verifying integrity of downloaded files using sha256sum...
- extracting downloaded archive...
- removing intermediate files...
subdirectory cs1302-hello successfully created
  1. Change to the cs1302-hello directory.

  2. Execute the tree command. You should see output similar to the following:

    tree
    
    .
    |-- bin
    `-- src
        `-- Hello.java
    
  3. Adjust the files/subdirectories within cs1302-hello using the appropriate Unix commands, to look like the following:

    tree
    
    .
    |-- bin
    `-- src
        `-- cs1302
            `-- example
                `-- Hello.java
    
Part 3: Compiling to Named Package
Starter Code
bundle1302 hello
- downloading cs1302-hello bundle...
- verifying integrity of downloaded files using sha256sum...
- extracting downloaded archive...
- removing intermediate files...
subdirectory cs1302-hello successfully created
Introduction

In large projects, code is organized into named packages similar to how you might organize your personal photos into subfolders.

To move code into a named package, there are two steps:

  • Place the .java files into the appropriate package directory (done in previous section)

  • Include an appropriate package statement at the top of each .java file (do this now).

Package Directory Setup

Let us assume we want the Hello class to be a member of the cs1302.example package:

Before: Default Package
tree
.
|-- bin
`-- src
    `-- Hello.java
After: Package cs1302.example
tree
.
|-- bin
`-- src
    `-- cs1302
        `-- example
            `-- Hello.java
  1. In your groups, discuss how to place the current Hello.java file into the desired package directory. This will likely involve more than one command. After coming to a consensus, perform the command(s) to make the necessary change(s).

  2. On your exit ticket: Note the commands that you used and why.

Package Statement Preparation

Here is the same "before and after" shown in the previous section:

Before: Default Package
tree
.
|-- bin
`-- src
    `-- Hello.java
After: Package cs1302.example
tree
.
|-- bin
`-- src
    `-- cs1302
        `-- example
            `-- Hello.java
  1. On your exit ticket: Discuss and note the implied Fully Qualified Name (FQN) of the Hello class both before and after moving it into the cs1302.example package. You should have two FQNs written down when you are done.

Emacs Aside

In the next section, you will be writing code using Emacs in class for the first time. While working through that section, try to incorporate the following keyboard shortcuts and commands:

Listing 8 Navigation
          M-v
          C-p
  M-b C-b  +  C-f M-f
          C-n
          C-v
  • Open File in Current Buffer: C-x C-f

  • Minimize / Suspend Emacs: C-z (run within Emacs)

  • Bring to Foreground: fg (run from terminal)

Adding the Package Statement
  1. Open your Hello.java file in emacs.

  2. Add the appropriate package statement at the top of the file.

  3. Save the file and exit emacs.

  4. On your exit ticket: Write down the complete package statement that you added to Hello.java and the emacs key bindings that you used to save the file and exit emacs.

Compiling Hello.java to a Named Package
  1. In your cs1302-hello directory, the Hello.java file should be located in the src/cs1302/example directory and have the correct package statement.

  2. Verify your directory structure and package statement using the tree command and the head command as seen below:

    tree
    
    .
    |-- bin
    `-- src
        `-- cs1302
            `-- example
                `-- Hello.java
    
    head src/cs1302/example/Hello.java
    
    package cs1302.example;
    
    ...
    
  3. Without using the cd command, compile Hello.java specifying bin as the destination for compiled code (i.e., the default package location for compiled code).

  4. On your exit ticket, write the command you used and include notes explaining the purpose of the -d bin part of the command and how the path to Hello.java relates to the desired directory structure within the bin directory. You can use the tree command after you compile to where Hello.class ends up to justify your reasoning.

Expected Tree Output After Compilation
tree
   .
   |-- bin
   |   `-- cs1302
   |       `-- example
   |           `-- Hello.class
   `-- src
       `-- cs1302
           `-- example
               `-- Hello.java
Solution
javac -d bin src/cs1302/example/Hello.java
Run Hello from cs1302-hello Directory
  1. Now, run the Hello program.

  2. Write on exit ticket: What command did you run? What happened when you executed that command? Be as detailed as possible.

    Solution
    java -cp bin cs1302.example.Hello
    
Run Hello from Home Directory
  1. Write on exit ticket: From your home directory (not cs1302-hello), what is the single command to run the Hello program?

    Solution
    java -cp cs1302-hello/bin cs1302.example.Hello
    
Part 4: Code Dependencies

Note

This section requires completion of the first three parts. If you missed class, please find a classmate who has those parts completed.

Starter Code
bundle1302 hello-v2
- downloading cs1302-hello-v2 bundle...
- verifying integrity of downloaded files using sha256sum...
- extracting downloaded archive...
- removing intermediate files...
subdirectory cs1302-hello-v2 successfully created
Adding a Dependency
  1. Navigate to the cs1302-hello-v2 folder if you aren't there already.

  2. Add a cs1302.utility package directory to your hierarchy. Hint: The utility directory will need to be inside of the cs1302 folder.

  3. Create a class called MyMethods in the cs1302.utility package. The file will need to be named MyMethods.java.

  4. Double check that you typed the class declaration. This class won't need a main method because it won't be run directly.

  5. Add a single, static method called max to the MyMethods class with the following signature:

    /**
     * Returns the larger of the two input parameters. If the parameters
     * are equal, either value can be returned.
     *
     * @param num1 the first number to check.
     * @param num2 the second number to check.
     * @return the larger of the two parameters.
     */
    public static int max(int num1, int num2) {
        // Your code here
    } // max
    
  6. Implement the body of the max method. The method should determine and return the bigger of two int values supplied as parameters to the method. These values will be supplied when you call the method in a later step. Note: You should not use the Scanner class inside of the MyMethods class.

  7. Run the tree command. You should see output similar to the following:

    tree
    
    .
    `-- src
        `-- cs1302
            |-- example
            |   `-- Hello.java
            `-- utility
                `-- MyMethods.java
    
Compiling MyMethods.java
  1. From cs1302-hello-v2, compile MyMethods.java and place the byte code in the bin directory. Remember, there are no dependencies when compiling MyMethods.java.

    Solution
    javac -d bin src/cs1302/utility/MyMethods.java
    
  2. Now that you've compiled both Hello.java and MyMethods.java, execute tree and look in the bin directory. Notice the directory hierarchy that was automatically created.

Calling max in Hello.java
  1. Modify the Hello class in the Hello.java file to print out the maximum of two values input by the user.

    Hint

    To accomplish this, in the main method of your Hello class, you should read two integers from a valid Scanner object and pass those values into the max method you created in the MyMethods utility class. In other words, you should call the max method in MyMethods from the main method in your Hello class and print the result.

    You must import MyMethods in Hello.java. Why?

    Solution
    Listing 9 In Hello.java
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
    
        System.out.print("Enter a number: ");
        int num1 = input.nextInt();
        System.out.print("Enter another number: ");
        int num2 = input.nextInt();
    
        // Use our new max method to find out which is bigger.
        int bigger = MyMethods.max(num1, num2);
        System.out.println(bigger + " is bigger");
    
    } // main
    
Compiling Hello with Dependencies
  1. Write on exit ticket: What is the command to compile the Hello class from the cs1302-hello-v2 directory and place the compiled code into bin?

    Hint

    There is now a dependency in Hello.java. It relies on the code from MyMethods, so the compiler needs to know where to find that class.

    Solution
    javac -d bin -cp bin src/cs1302/example/Hello.java
    
  2. Execute the tree command from directly within your cs1302-hello-v2 directory. If the previous steps were executed correctly, you should see the following output:

    Note: If you see any tilde (~) files, those are just backup copies of older versions of your files. You can ignore those.

    tree
    
    .
    |-- bin
    |   `-- cs1302
    |       |-- example
    |       |   `-- Hello.class
    |       `-- utility
    |           `-- MyMethods.class
    `-- src
        `-- cs1302
            |-- example
            |   `-- Hello.java
            `-- utility
                `-- MyMethods.java
    
Running Hello with Dependencies
  1. Write on exit ticket: What is the command to run Hello?

    Solution
    java -cp bin cs1302.example.Hello
    
  2. Run your code to make sure everything is working properly. Demonstrate to your instructor if they are available.

Part 5: Designing on Paper (Exit Ticket)

Note

Close your laptops for this section. Work with your group to analyze the class designs and write your code solution by hand on your exit ticket.

Class Diagrams & Problem Description

Consider the following UML class diagram showing a Course class, a Student class that references a Course, and a MyMethods utility class:

hide circle
hide empty members
set namespaceSeparator none
skinparam classAttributeIconSize 0
skinparam genericDisplay old
skinparam defaultFontName monospaced
skinparam defaultFontStyle bold
skinparam class {
    BackgroundColor LightYellow
    BackgroundColor<<interface>> AliceBlue
}
class cs1302.model.Course {
  - name: String
  - prof: String
  + <<new>> Course(name: String, prof: String)
  + getName(): String
  + getProf(): String
}

class cs1302.model.Student {
  - name: String
  - course: Course
  + <<new>> Student(name: String, course: Course)
  + getName(): String
  + getCourse(): Course
}

class cs1302.utility.MyMethods {
  + {static} numTakingCourse(students: Student[], courseName: String): int
}

cs1302.model.Student --> cs1302.model.Course : uses
cs1302.utility.MyMethods --> cs1302.model.Student : uses

Handwritten Code Implementation
  1. On your exit ticket: Assume the Course and Student classes provide standard constructors and getter methods as shown in the diagram above.

  2. Write out the full implementation for the numTakingCourse method in MyMethods:

    Listing 10 In MyMethods.java
    /**
     * Counts how many students in the array are currently taking the specified course.
     *
     * @param students the array of students to check
     * @param courseName the name of the course to match
     * @return the number of students taking the course
     */
    public static int numTakingCourse(Student[] students, String courseName) {
        // Your handwritten code here
    } // numTakingCourse
    
    Example Driver in Another Package
     1package cs1302.example;
     2
     3import cs1302.model.Course;
     4import cs1302.model.Student;
     5
     6public class Driver {
     7
     8    public static void main(String[] args) {
     9
    10        // Create some courses
    11        Course cs1 = new Course("CSCI 1301", "Cotterell");
    12        Course cs2 = new Course("CSCI 1302", "Barnes");
    13
    14        // Create some students
    15        Student alice = new Student("Alice", cs1);
    16        Student bob = new Student("Bob", cs1);
    17        Student charlie = new Student("Charlie", cs2);
    18        Student diana = new Student(null, cs2);  // Student with null name
    19        Student eve = new Student("Eve", null);  // Student with null course
    20
    21        // Put them in arrays - some arrays will be null,
    22        // some will contain null elements
    23        Student[] roster1 = new Student[]{ alice, bob, charlie, diana, eve };
    24        Student[] roster2 = null;
    25        Student[] roster3 = new Student[]{ alice, bob };
    26        Student[] roster4 = new Student[]{ alice, null, bob };
    27
    28        int num1 = cs1302.utility.MyMethods.numTakingCourse(roster1, course1);
    29        int num2 = cs1302.utility.MyMethods.numTakingCourse(roster1, course2);
    30        int num3 = cs1302.utility.MyMethods.numTakingCourse(roster1, course3);
    31        int num4 = cs1302.utility.MyMethods.numTakingCourse(roster1, course4);
    32        int num5 = cs1302.utility.MyMethods.numTakingCourse(roster2, course1);
    33        int num6 = cs1302.utility.MyMethods.numTakingCourse(roster3, course1);
    34        int num7 = cs1302.utility.MyMethods.numTakingCourse(roster4, course1);
    35
    36    } // main
    37
    38} // Driver
    

    Considerations

    • What if the students array or the courseName parameter is null?

    • What if an element within the students array is null?

    • What if a student has not been assigned a course (i.e., s.getCourse() returns null)?

    • How should you compare two String objects for equality in Java?

    Solution
    Listing 11 In MyMethods.java
    public static int numTakingCourse(Student[] students, String courseName) {
        int count = 0;
        if (students == null || courseName == null) {
            return 0;
        } // if
        for (Student s : students) {
            if (s != null && s.getCourse() != null && courseName.equals(s.getCourse().getName())) {
                count++;
            } // if
        } // for
        return count;
    } // numTakingCourse
    

Additional Practice: Named Packages

Additional Practice: Named Packages

To see sample solutions, toggle "Show Solutions" above.

Sample solutions not included, because "Show Solutions" was not toggled before printing.

Activity Objectives

Learn how to organize code using packages, compile Java programs with proper directory and classpath configurations, and execute them using fully qualified names.

Question: Running a Program

You are working with a file with the relative path:

src/pkg/example/myapp/Welcome.java

which includes the first line:

package pkg.example.myapp;

What is the FQN of the class? After compiling it to the bin/ directory, what command would you use to run it from inside the project/ folder?

Solution

FQN: pkg.example.myapp.Welcome

Command:

java -cp bin pkg.example.myapp.Welcome

Explanation:

The fully qualified name (FQN) includes the package and class name. When running from the project/ folder, the classpath must point to the bin/ directory where the class was compiled.

Question: Compiling and Running

Consider the following file structure. Assume you are in the student directory.

Listing 12 You are in the student directory.
student     // you are here
`-- cs1302-packages
    `-- src
        `-- cs1302
            `-- hello
                `-- HelloWorld.java
  1. Without changing directories, what exact command would you type to compile HelloWorld.java to bin assuming it is in the cs1302.hello package and the appropriate package statement is included in the code?

    Solution
    javac -d cs1302-packages/bin cs1302-packages/src/cs1302/hello/HelloWorld.java
    
  2. Without changing directories, how would you run HelloWorld?

    Solution
    java -cp cs1302-packages/bin cs1302.hello.HelloWorld
    

    Explanation:

    As the file is now compiled, the FQN must match the package and class name, and the classpath must include cs1302-packages/bin to provide a valid path to the compiled class hierarchy.