Contents:

The purpose of this homework is to help you set up your development environment, get reacquainted with Java, and start getting familiar with tools you will use for the rest of the course. Although the homework description is long, we expect the step-by-step instructions will make doing the homework less overwhelming than reading it may be.

This homework links to (the middle of) some other handouts at many points. For convenience, here is the list of these handouts:

(It also links to various Java files and API documentation files that are not listed above.)

You are free to get help from anyone on any portion of this homework. That is, the standard collaboration restrictions do not apply to this homework. You will need to know this material for the remainder of the quarter, however, so make sure you understand thoroughly the tools and concepts in this homework.

We encourage you to finish this homework well before its due date. If you are having trouble with finishing on time, get in touch with the staff immediately so we can help you get back on track.

Problem 1: Choosing and Setting-Up a Development Environment

You first need to decide what computer(s) and development environment(s) you will use for the course, or at least for this homework. We strongly recommend using the Eclipse IDE in CSE331, but we will not check whether or not you do so. We also provide instructions for working from the Linux command line.

You can use the CSE department's instructional labs by going to the basement of the Allen Center; or access the facilities remotely; or install a virtual machine on your own computer that is just like the department's Linux machines; or install Java, Eclipse, and other necessary tools on your own computer. There are trade-offs among these choices: the Working At Home document explains the trade-offs and provides the instructions for each option. Please read this document and setup the development environment that you want, again Eclipse IDE is highly recommended.

Note that even if you mostly do not use the department's machines, you should still connect to attu to validate your assignment after you submit it, as described near the end of this homework.

Once you have chosen and prepared a development environment, you should set it up for CSE331 use. See Starting Eclipse and follow any instructions that are applicable. (Note: if you switch development environments later in the quarter, revisit these instructions.)

Using the correct compiler: Eclipse is a widely-used Java development environment with a number of excellent features including integration with Git, Ant, and JUnit — tools that we use in CSE331. However, instead of using the official Java compiler (“javac”) from Oracle/Sun, Eclipse uses an Eclipse-specific Java compiler. Bugs in either compiler are very rare, but if they occur they can cause the same code to have different behavior with different compilers. Course staff will compile and grade your code using the javac compiler, so you should make sure that your code behaves correctly when compiled with javac. One way to verify this is to run the ant validate command from attu as explained more at the end of this assignment. You can also read Compiling Java Source Files for more details on javac.

Refer to the Eclipse quick reference to learn about some of Eclipse's handy features.

Problem 2: Obtaining files from GitLab

Throughout the course, you will receive starter code and submit your assignments through CSE's GitLab server (git). git is a version control system that lets software engineers backup, manage, and collaborate on large software projects. GitLab is a CSE department server that provides git repositories for students in CSE331 and many other classes and projects (You will learn more about git in section.)

For this problem, you should follow the setup instructions in the Version Control handout, which describes how to “clone” (copy) your CSE331 GitLab repository to a local machine. This handout also contains instructions for pulling from, committing to, and tagging your repository. You should familiarize yourself with these commands as you will need to use them throughout this homework and the rest of the course.

Problem 3: Warm-Up Exercise—HolaWorld

For this problem, you will fix some buggy code we provide.

Editing and Compiling Source Files

See Editing and Compiling Source Files to help learn how to perform the following basic tasks: adding new files to your directory structure, compiling Java code, and reading the Java compiler's output (which may indicate errors).

Also see the CSE331 Java Style Guide, which describes some standards for Java style that we will expect you to follow.

Fixing HolaWorld

Try to compile the provided code in HolaWorld.java. You should see compilation errors for this file. (And possibly in hw3/test/RandomHelloTest.java too; if so, ignore these for now since we will fix them in the next part.) In particular, the lines:

        System.out.println(world.);

and:

        return SPANISH_GREE;

are problematic. (If you're using the the Ant builder, you may see the second error only after you've fixed the first one.) If you are using Eclipse, these errors will be marked with red squiggly lines in HolaWorld.java, and HolaWorld.java itself will be marked with a red crossmark in the Package Explorer.

Fix these errors and run HolaWorld.

After you've fixed the errors and run the code, it would be a good time to commit your changes to GitLab.

Problem 4: Your first Java class—RandomHello

Create a Java class with a main method that will randomly choose, and then print to the console, one of five possible greetings that you define.

Create the file RandomHello.java, which will define a Java class RandomHello that will reside in the Java package hw3; that is, its file name is YourWorkspaceDirectory/cse331/src/hw3/RandomHello.java.

Java requires every runnable class to contain a main method whose signature is public static void main(String[] args) (for example, the main methods in HelloWorld and in HolaWorld).

A code skeleton for the RandomHello class is shown below. Eclipse will generate some of this skeleton for you when you create the new RandomHello class.

RandomHello.java:

package hw3;

/**
 * RandomHello selects a random greeting to display to the user.
 */
public class RandomHello {

    /**
     * Uses a RandomHello object to print
     * a random greeting to the console.
     */
    public static void main(String[] argv) {
        RandomHello randomHello = new RandomHello();
        System.out.println(randomHello.getGreeting());
    }

    /**
     * @return a random greeting from a list of five different greetings.
     */
    public String getGreeting() {
        // YOUR CODE GOES HERE
    }
}

This skeleton is meant only to serve as a starting point; you are free to organize it as you see fit.

No Need to Reinvent the Wheel

Don't write your own random number generator to decide which greeting to select. Instead, take advantage of Java's Random class. (This is a good example of the adage "Know and Use the Libraries" as described in Chapter 7 of Joshua Bloch's Effective Java. Learning the libraries will take some time, but it's worth it!)

Type the following into the body of your getGreeting() method:

Random randomGenerator = new Random();

This line creates a random number generator (not a random number, which comes later, but a Java object that can generate random numbers). In Eclipse, your code may be marked as an error by a red underline. This is because the Random class is defined in a package that has not yet been imported (java.lang and hw3 are the only packages that are implicitly imported). Java libraries are organized as packages and you can only access Java classes in packages that are imported. To import java.util.Random, add the following line under the line package hw3; at the top of your file (after the package hw3; declaration):

import java.util.Random;

This will import the class Random into your file. To automatically add all necessary imports and remove unused imports, Eclipse lets you type CTRL-SHIFT-O to Organize your imports. Because there is only one class named Random, Eclipse will figure out that you mean to import java.util.Random and will add the above line of code automatically. (If the name of the class that needs to be imported is ambiguous — for example, there is a java.util.List as well as a java.awt.List — then Eclipse will prompt you to choose the one to import.)

Using java.util.Random

Read the documentation for Random's nextInt(int n) method by going to the Java API and selecting Random from the list of classes in the left-hand frame. Many classes also let you pull up documentation directly in Eclipse. Just hover over the class or method name and press SHIFT+F2.

Use the nextInt(int n) method to choose your greeting. You don't have to understand all the details of its behavior specification, only that it returns a random number from 0 to n-1.

One way to choose a random greeting is using an array. This approach might look something like:

String[] greetings = new String[5];
greetings[0] = "Hello World";
greetings[1] = "Hola Mundo";
greetings[2] = "Bonjour Monde";
greetings[3] = "Hallo Welt";
greetings[4] = "Ciao Mondo";

The main method in the skeleton code above prints the value returned by getGreeting. So if you insert code in getGreeting to select a greeting randomly, when the class is run it will will print that greeting.

When you are finished writing your code and it compiles, run it several times to ensure that all five greetings can be displayed.

Again, now it would be a good idea to add your new class to version control and commit your code.

Problem 5: Testing Java Code with JUnit

Screenshot: Run Junit from Eclipse

Testing is essential for writing quality software, so it's important for testing to be a convenient part of software development. JUnit is a framework for creating unit tests in Java. A unit test is a test for checking that a given method in a class conforms to its specification for an input. This problem provides a quick overview and simple example of how JUnit works. (Unit testing will be more significant in later assignments.)

Open both hw3/Fibonacci.java and hw3/test/FibonacciTest.java. From the comments, you can see that FibonacciTest is a test of the Fibonacci class.

Now run the JUnit test hw3.test.FibonacciTest.

A window or panel with a menacing red bar will appear, indicating that some of the tests in FibonacciTest did not complete successfully (see screenshot at right). The top pane displays the list of tests that failed, while the bottom pane shows the Failure Trace for the highlighted test. The first line in the Failure Trace should display an error message that explains why the test failed. (The author of the test code creates this error message.)

If you click on the failure testThrowsIllegalArgumentException, the bottom pane will switch to the appropriate error message. In this example, the first line of the failure trace shows that Fibonacci.java improperly threw an IllegalArgumentException when tested with zero as its argument. (You may have to scroll to the right to see this.) If you double-click on the name of a test in the top pane, Eclipse will jump to the line where the failure occurred in the editor pane. Figure out the problem in Fibonacci.java, fix it, and rerun the JUnit test. Eclipse will automatically rebuild when you make changes, but if you are running JUnit from the command line, you must manually rebuild (compile) Fibonacci.java before you rerun JUnit. This can be done by rerunning the ant command (which also compiles the files) or by following the compiling instructions and then clicking the “Run” button.

Use the information in the Failure Trace box to help you continue debugging Fibonacci. Keep a record of what you did to debug Fibonacci as you will have to answer questions about your debugging experience in the next problem. After you have fixed all the problems in Fibonacci, you should see a bright green bar instead of a red one when you run FibonacciTest.

Now look at the JUnit tests that we wrote for HolaWorld and RandomHello. They are called HolaWorldTest and RandomHelloTest, respectively. Ensure that your modified code passes these tests before you turn in your homework.

Problem 6: Answering Questions About the Code

Find the file named hw3/answers.txt in your hw3 folder. Open this file and add answers to the following questions under Problem 6:

  1. Why did Fibonacci fail the testThrowsIllegalArgumentException test? What (if anything) did you have to do to fix it?
  2. Why did Fibonacci fail the testBaseCase test? What (if anything) did you have to do to fix it?
  3. Why did Fibonacci fail the testInductiveCase test? What (if anything) did you have to do to fix it?

Problem 7: Getting a Real Taste of Java—Balls and Boxes

Until now, we have only been introducing tools. This problem delves into a real programming exercise. This problem will likely be somewhat challenging for most of you. Don't be discouraged. We're here to help, and we expect that time spent now will pay off significantly during the rest of the course.

As you work on this problem, record your answers to the various questions in the answers.txt that you first edited in the previous section of this assignment.

  1. Warm-Up: Creating a Ball:

    Look at Ball.java. A Ball is a simple object that has a volume.

    We have included a JUnit test BallTest to help you. Moreover, one of Eclipse's warnings should help you find at least one of the bugs without even referring to the JUnit results.

  2. Using Pre-Defined Data Structures:

    Next, create a class BallContainer. As before, skeleton code is provided (see BallContainer.java). A BallContainer is a container for Balls. BallContainer should support the following methods: your task is to fill in the code to implement these methods correctly:

    1. add(Ball)
    2. remove(Ball)
    3. getVolume()
    4. size()
    5. clear()
    6. contains(Ball)
    The specifications for these methods are found in the javadoc file for BallContainer.

    In BallContainer, we use a java.util.Set to keep track of the balls. This is a great example of using a predefined Java data-structure to save yourself significant work. Before implementing each method, read the documentation for Set. Some of your methods will be as simple as calling the appropriate predefined methods for Set.

    To help you out, we have included a JUnit test called BallContainerTest.java.

    Before you start coding, please take time to think about the following question (which you need to answer in the text file):

    There are two obvious approaches for implementing getVolume():
    1. Every time getVolume() is called, go through all the Balls in the Set and add up the volumes. (Hint: one solution might use a for-each loop to extract Balls from the Set.)
    2. Keep track of the total volume of the Balls in BallContainer whenever Balls are added and removed. This eliminates the need to perform any computations when getVolume is called.

    Which approach do you think is the better one? Why?

  3. Implementing a Box:

    In this problem, you will do a little more designing and thinking and a little less coding. You will implement the Box class. A Box is also a container for Balls. The key difference between a Box and a BallContainer is that a Box has only finite volume. Once a box is full, we cannot put in more Balls. The size (volume) of a Box is defined when the constructor is called:

    public Box(double volume);
    

    Since a Box is in many ways similar to a BallContainer, we internally keep track of many things in the Box with a BallContainer, allowing us to reuse code. Many of the methods in Box can simply “delegate” to the equivalent in BallContainer. For example, removing from a Box cannot cause it to exceed its volume limit. This design of having one class contain an object of another class and reusing many of the methods is called composition.

    (Optional Note: You may wonder why we did not make Box extend BallContainer via inheritance. That is, why did we not make Box a subclass of BallContainer? We will discuss this much more deeply later in the course, but the key idea is that Box is not what we call a true subtype of BallContainer because it is in fact more limited than BallContainer (a Box can only hold a limited amount); hence, a user who uses a BallContainer in his code cannot simply substitute that BallContainer with a Box and assume the same behavior. (The code may cause the Box to fill up, but he did not have this concern when using a BallContainer). For this reason, it is unwise to make Box extend BallContainer.)

    In addition to the constructor described above, you will need to implement the following new methods in Box:

    1. add(Ball)
    2. getBallsFromSmallest()

    The specifications for these methods can be found in the javadoc file for Box.

    A few things to consider before you start writing code:

    Also, answer the following questions in your answers.txt file:

    1. There are many ways to implement getBallsFromSmallest(). Briefly describe at least two different ways. Your answers should differ in the implementation of Box, not in lower-level implementation (for example, using an insertion sort instead of a selection sort is a lower-level implementation because it does not affect how Box is implemented). Hint: think about different places in the Box class where you could add code to achieve the desired functionality.
    2. Which of the above ways do you think is the best? Why?

    There is no one correct answer. Our intent is to help you fight that urge to code up the first thing that comes to mind. Remember: More thinking, less coding.

Problem 8: Turning In Your Homework

Each homework will indicate exactly what to turn in a Section titled “What to Turn In”. This typically includes Java source files (that you change or create) and text files.

You will turn in your homeworks by committing changes and pushing those changes to your GitLab repository. To do so,

You can commit and push changes as many times as you want while working on the assignment. That is a good way to store backup copies of your work in the CSE GitLab repository.

When you have committed and pushed all of your changes and are done with the assignment, you should create a git tag in your repository named hw3-final and push that tag to your repository. Once you have committed and pushed that tag, your assignment has been submitted. The staff will grade the files in your repository that are labeled with that tag. Be sure you remember to add/commit/push your files and the tag!

For each homework, we strongly recommend that you validate what you have turned in by running the provided validation checks on attu. Read about validate now and be sure to get it working for the sake of this and future homeworks. While validate does not ensure your homework is perfect, it performs important sanity checks, like seeing if your code compiles and if expected files are present in the repository. It is in your interest to do these checks. They often can catch minor errors that can cause programs to fail spectacularly when they are evaluated, which can cause a program that is basically correct to receive a score far lower than it should have gotten.

As the detailed instructions for validate indicate, you want to make sure validate completes without errors. If validation was successful, the output will end with something like:

...
BUILD SUCCESSFUL
Total time: 9 seconds

If there is a problem, the output will end with something like:

...
BUILD FAILED
/homes/iws/username/workspace331/cse331/src/common.xml:129: exec returned: 1

and will indicate, before that, what is wrong. Read the output carefully to find this information.

Validate your homework and fix problems as many times as necessary until there are no errors. If you push additional changes to your repository to fix problems you will need to reapply the hw3-final tag so it references the proper version of the code in your repository. See the version control documentation for details. You have now successfully turned in your CSE331 homework.

What to Turn In

Your TA should be able to find the following in the src directory of Gitlab:

Please include your first and last name in every text file you turn in (i.e., files ending with .txt). In particular, be sure to update answers.txt to include your name as well as the expected answers.

Optional: Debugger Tutorial

In this part, you will learn about Eclipse's built-in debugger. A debugger can help you debug your program by allowing you to "watch" your program as it executes, one line at a time, and inspect the state of variables along the way. Using a debugger can be much more powerful and convenient than littering your program with statements that print output.

One of the most useful features of a debugger is the ability to set breakpoints in your program. When you run your program through the debugger, it will pause when it reaches a line with a breakpoint. You can inspect the current state of variables, then continue running your program normally or step through one line at a time to watch the variables change.