Java代写: 软件设计与实现

java基础软件设计, 熟悉java.util.Random模块,单元测试JUnit等。

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 policy does 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. If you choose to work from home on your personal machine please follow the basic setup instructions to set up your development environment. For more information and trade-offs among these choices: the Working At Home document explains the trade-offs and provides the instructions for each option. 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 a development environment, you should set it up for CSE331 use. See the Starting Eclipse instructions. (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 use the Ant build file we provide for each homework. See Compiling Java Source Files for details.

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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.

    • What is wrong with Ball.java? Fix the problems with Ball.java and document your work in answers.txt.

    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:

    • You shouldn’t need to implement your own sorting algorithm. Instead, take advantage of the Java API (remember: “Know and Use the Libraries”).
    • Also, you shouldn’t need to change your implementation of BallContainer or Ball for this problem. In particular, you should not implement the Comparable interface. If you are tempted to do so, consider using Comparator instead. Comparator is a companion interface to Comparable and is used throughout the Java libraries: check out the sort methods in java.util.Collections as an example.
    • If you do make any changes to BallContainer or Ball for this problem, then explicitly document what changes you made and why in answers.txt.
    • Be cautious if you plan on using Java’s TreeSet; remember that TreeSet does not store duplicates, and if you provide a TreeSet with a Comparator, it will use that Comparator to determine duplication. See the TreeSet API documentation for more details.
    • Before you start working on getBallsFromSmallest(), we recommend strongly that you consider using Iterator.
    • The JUnit test BoxTest should help you. However, we do not guarantee that the tests we provide will catch all bugs.
    • And, naturally, don’t forget to commit your code more than occasionally.

    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,

  • Add and commit all changed (or newly-added) files.
  • Push the committed changes to the repository so they are stored in GitLab as well as being updated locally.

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.

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

  • hw3/HolaWorld.java that works as described in Problem 5 with no compilation errors
  • hw3/RandomHello.java that prints out one of five random messages when its main method is executed
  • hw3/Fibonacci.java that passes the three tests in hw3/test/FibonacciTest.java (Note that you should not edit hw3/test/FibonacciTest.java to accomplish this task.)
  • hw3/Ball.java, hw3/BallContainer.java and hw3/Box.java that pass their respective JUnit tests (Again, you should not modify the JUnit tests, though you are encouraged to read the code to understand what they test.)
  • hw3/answers.txt containing answers to the questions in Problems 6 and 7.

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.

  • Open Adder.java. This simple program is supposed to print the sum of two user-provided integers. Try running it a few times (or reading the source code) and you’ll see that it doesn’t behave as expected.
  • Double-click in the left-hand margin of the class next to the line return x - y; A blue circle should appear, indicating a breakpoint. (Double-clicking again removes the breakpoint.)
  • Run the program in debug mode by using F11, Run >> Debug, or the green bug icon in the toolbar. As before, enter two ints (say, 3 and 4) in the console when prompted. When your program hits the breakpoint, Eclipse asks if you want to open the Debug perspective. Choose yes.
  • The debug perspective looks overwhelming at first, but don’t worry! In the top-right panel, select the “Variables” tab and you’ll see the names and values of all variables in the current context. The top-left panel (“Debug”) shows where the program is currently paused, where the current method was called, and so on. (This is called the stack trace). Double-click on a method name to see the corresponding line in the panel below, where you can view and edit your source code. Finally, the bottom-left panel shows the console window.

    What are all the names and values listed in the “Variables” panel? What does the “Debug” panel list as the current method and line number? (Write down the text that was highlighted when the Debug perspective first opened.)

  • Immediately above the “Debug” panel are several buttons for running your program. Mouse over each one for a description. “Resume” (green arrow) causes your program to continue executing normally until it finishes or hits another breakpoint. If you want to monitor what happens shortly after the breakpoint, use “Step Into” and “Step Over” (yellow arrows). “Step Over” executes the current line and pauses on the next line. “Step Into” enters any method called on the current line so you can execute that method line-by-line. (To finish the current method and jump back to the caller, use “Step Out.”) Hit “Step Over” once to execute the return statement and exit computeSum. Hit “Step Over” again to progress to the next line.

    What are all the names and values listed in the “Variables” panel after each of the two step overs?

  • Hit “Resume” to allow the program to finish executing. Return to the default Java perspective by clicking “Java” in the top-right corner or by going to Windows >> Open Perspective >> Other... and selecting Java (default).

kamisama wechat
KamiSama