Fundamentals of Computer Science II (CSC-152 99F)


Notes on Exam 1: Java Fundamentals


Problems

A. Computing Averages

Carl and Carla Caffeinated have decided to combine ideas that we've recently seen (or will see) and have built a program that averages values typed on the command line. Here's the class, Average, that they've come up with.


import SimpleOutput;

/**
 * Compute the average of a list of numbers entered on the command
 * line.  For example, to compute the average of a, b, and c, you
 * would write
 *   % java Average a b c
 *
 * @author Carla Caffeinated
 * @author Carl Caffeinated
 * @author Samuel A. Rebelsky
 * @author YOUR NAME HERE
 * @version 1.0 of September 1999
 */
public class Average {
  public static void main(String[] args) {
    int sum = 0;	// The sum of all the values entered.
    int count = 0;	// The number of values entered.
    SimpleOutput out = new SimpleOutput();
    
    // Step through the values, adding each in turn.  Skip those
    // that aren't valid.
    for (int i = 0; i < args.length; i = i+1) {
      try {
        sum = sum + Integer.parseInt(args[i]);
        count = count + 1;
      }
      catch (NumberFormatException nfe) {
        // Skip it.
        i = i + 1;
      }
    } // for
  
    // Print the average.
    out.println("The average grade is: " + (sum/count));
  } // main(String[])
} // class Average



In all their tests, the program seems to work fine

% ji Average 3 4 5
The average grade is: 4
% ji Average 5 4 3
The average grade is: 4
% ji Average 10 100
The average grade is: 55
% ji Average -10 20
The average grade is: 5
% ji Average -10 aardvark zebra 20
The average grade is: 5
% ji Average 10.5 9.5 10
The average grade is: 10

Unfortunately, they've made the mistake of turning in their program without enough testing. They get their program back with a D and the note that

I'm sure the average of 1, 1, and 3 is closer to 1.67 than 1. I'm also sure that the average of 0, 100.1, and 200.2 is not 0. Please think more about possible problems and errors.

The Caffeinateds return their code and, sure enough, when they try the examples, things work ``oddly''.

% ji Average 1 1 3
The average grade is: 1
% ji Average 0 100.1 200.2
The average grade is: 0

1. Basic Errors

Your first step is to help the Caffeinateds deal with the errors that their instructor has identified.

A Solution

All of the problems seem to have to do with instances in which the inputs or outputs involve fractional parts. It is likely that this is because the program use ints rather than floats or doubles.

Repairs:

Some Notes

For this problem, you were to deal with all of the problems that the instructor observed. Some of you left some of the problems (e.g., dealing with doubles as in put) to part 2, which meant that you ignored the other issues in part 2. I didn't take off for you leaving you fix to part 2, but I did take off if you didn't handle other issues.

Part of the problem was to summarize the difficulties. If you neglected to summarize the difficulties, I took off 5 points.

2. Other Errors

Depending on how you dealt with the previous errors, there is at least one (and possibly more) logical errors in their program which will lead it to behave ``inappropriately''. Identify those errors and update the code so that it behaves correctly.

A Solution

Problem: The program does not check if there are no numbers to average. If there are none, it reports that the average grade is ``NaN'' (not a number).

% ji Average
The average grade is: NaN

Solution: Give the user a clearer error message.

    if (count == 0) {
      out.println("I need values to average.");
      out.println("Usage:");
      out.println("  java Average val1 val2 ... valn");
    } // if (count == 0)

Here's a sample of the updated output.

% ji Average
I need values to average.
Usage:
  java Average val1 val2 ... valn

Problem: The user may not understand that non-numeric values are not counted. After all, what's wrong with entering ``five''?

Solution: Print out a note when you catch an exception. Here's some new sample output.

% ji Average 1 2 three
Skipping 'three'
  [Values must be numbers in 'digit form']
The average grade is: 1.5

Problem: In spite of all the updates, the program still behaves incorrectly when invalid values are entered.

% ji Average zero 1 100
Skipping 'zero'
  [Values must be numbers in 'digit form']
The average grade is: 100.0

Similarly, n examples with multiple invalid values, we only get error messages some of the time. Here's one example that prints both error messages and one that does not.

% ji Average 5 one 2 ten
Skipping 'one'
  [Values must be numbers in 'digit form']
Skipping 'ten'
  [Values must be numbers in 'digit form']
The average grade is: 5.0
ji Average one two 5
Skipping 'one'
  [Values must be numbers in 'digit form']
The average grade is: 5.0

Solution: A closer analysis of the examples suggests that one of the input values is being skipped whenever there's an error. This means that the error most-likely happens in the code for handling that error. What does that code do? We've just made it print an error message. Printing should not otherwise affect the program. But there's also the line

        i = i + 1;

Do we need that line? Each time through the loop, iis incremented. This seems to do an extra increment. Not a good idea. Drop the line. Here's the new output.

% ji Average one two 5
Skipping 'one'
  [Values must be numbers in 'digit form']
Skipping 'two'
  [Values must be numbers in 'digit form']
The average grade is: 5.0
% ji Average one 2 three 4
ji Average one 2 three 4 
Skipping 'one'
  [Values must be numbers in 'digit form']
Skipping 'three'
  [Values must be numbers in 'digit form']
The average grade is: 3.0

We're basically done. Here's the final version of my program.


import SimpleOutput;

/**
 * Compute the average of a list of numbers entered on the command
 * line.  For example, to compute the average of a, b, and c, you
 * would write
 *   % java Average a b c
 *
 * This is a modified version of the program found on the Web at
 * http://www.math.grin.edu/~rebelsky/Courses/CS152/99F/Examples/Exam1/Average.java
 * All modifications are listed below.
 *
 * @author Carla Caffeinated
 * @author Carl Caffeinated
 * @author Samuel A. Rebelsky
 * @version 1.0 of September 1999
 */
public class Average {
  public static void main(String[] args) {
    // The following line was modified by Sam Rebelsky on
    // Friday, September 24, 1999 as part of answer A.1.
    double sum = 0;	// The sum of all the values entered.
    int count = 0;	// The number of values entered.
    SimpleOutput out = new SimpleOutput();
    
    // Step through the values, adding each in turn.  Skip those
    // that aren't valid.
    for (int i = 0; i < args.length; i = i+1) {
      try {
        // The following line was modified by Sam Rebelsky on
        // Friday, September 24, 1999 as part of answer A.1.
        sum = sum + (new Double(args[i]).doubleValue());
        count = count + 1;
        // The next few lines were added by Sam Rebelsky on
        // Friday, 24 September 1999, as part of an attempt to
        // understand difficulties in the program.
      }
      catch (NumberFormatException nfe) {
        // The next two statements were added by Sam Rebelsky on
        // Friday, 24 September 1999 to give the user more
        // information on values that are skipped.
        out.println("Skipping '" + args[i] + "'");
        out.println("  [Values must be numbers in 'digit form']");
        // The code that was here was removed by Sam Rebelsky on
        // Friday, 24 September 1999 to correct a logical error.
      }
    } // for
  
    // Print the average (assuming that it can be computed).
    // Except as mentioned below, the following lines were 
    // added by Sam Rebelsky on 24 September 1999 in response
    // to problem A.2.
    if (count != 0) {
      // Original line
      out.println("The average grade is: " + (sum/count));
    }
    // You can't compute an average of 0 values.  Tell the user.
    else {
      out.println("I need values to average.");
      out.println("Usage:");
      out.println("  java Average val1 val2 ... valn");
    } // No values entered
    // End of additions  from 24 September 1999
  } // main(String[])
} // class Average



Some Notes

As the discussion above suggests, the line that reads

i = i+1;

is incorrect. The best solution is to remove it. If you did not remove it, your program has serious errors, as you will discover if you try any of the following:

% ji Average hello 1 10 20
% ji Average hello 5
% ji Average one two three

This is a serious enough problem that I took off 7 points if you failed to identify and correct it.

The incorrect way to solve this problem is to change the line to read

i = i;

Why is this incorrect? Because the line is essentially meaningless. It says ``keep i the same'' and will only serve to confuse the reader. I took off 2 points if you left this odd line.

We'd talked about potential troubles in average computations earlier (in our discussion of exceptions) and we'd all noted that it is an error to have no valudes to average. Your program should have printed a useful error message. I took off 5 points if you didn't print an error message on no input.

I expected that you would observe that your users would not necessarily know when their input was being skipped. Hence, you should have printed an error message when you caught the exception. If you failed to do so, I took off 2 points.

A few of you were able to identify these errors, but not to fix them. I took off 5 points in such cases.

Since I emphasized formatting of code on problem C, I expected that you would be careful on your formatting on problem A. Some of you weren't and I took off about 2 points.


B. A Registration System

As you may know, the registrar's office recently upgraded to a new system. Suppose that the registrar had instead decided to hire us to build the new system. We would, of course, begin that task by identifying important objects in the system.

Some Notes

We went over some issues in class. I'm not going to take the time to include a detailed sample solution.

1. A Student Class

List the fields and methods you might expect to find in the Student class. Don't worry about implementing the methods; just summarize their purpose. If you use another class as the type of a field, make sure that you describe that class in your answer to B.2.

Some Notes

2. Core Objects

What are the other core data classes you might expect to find in a registration system? Don't worry about the objects involved in the interface. Rather, consider the underlying objects that store the important information, such as Student. For each class, list the name and a summary of its purpose and content.

3. A Transcript Story

Write a short narrative describing the objects and methods that might be involved in the operation ``Print T. Smith's Transcript''. Your narrative might begin with something like the following.

After connecting to the system and entering account and password, the registrar finds the object, current, in class Student that corresponds to T. Smith. The registrar then calls current.toString() to generate a printable version of the transcript. The toString() method first calls getGraduationYear() (also in class Student) ...


C. Correcting and Commenting Code

Our friends the Caffeinateds have realized that they don't know how to indent and comment code. Please turn their Book.java into something that is more readable. You should certainly add comments, fix the badly formatted code, add whitespace where appropriate, and reorganize the code so that similar things are near each other. Your goal is to create a class that is likely to meet my high standards of indentation, organization, uniformity, and commenting. Use the existing code (which does work); do not rewrite from scratch.


public class Book {
  public int getNumChapters() {
    return this.numChapters; 
  }
  public Book() { 
    this.chapters = new String[20]; 
    this.numChapters = 0; 
  }
  public String getTitle() { 
    return this.title; 
  }
  protected String title;

// Needs significant formatting help!
public String getAuthor() { return
this.author; } protected String author; public String
toString() { String
stuff = "\"" + 
this.title + "\" by " 
+ this.author + "\n";
  for (
int i = 0;
i < numChapters; ++i) { if (chapters[i] != null) {
stuff = stuff + "  " + (i+1) + ": " + chapters[i] + "\n"; 
                          }
}
return stuff; } int numChapters;

  public Book(int numChapters) {
    this.chapters = new String[numChapters]; 
    this.numChapters = 0; 
  }
  public Book(String author, String title) {
    this.author = author; 
    this.title = title; 
    this.chapters = new String[20]; 
    this.numChapters = 0; 
  }

  protected String[] chapters;
  
  public void addChapter(String chapterName)
    throws Exception
  {
    if (numChapters >= chapters.length) { 
      throw new Exception();
    }
    chapters[numChapters] = chapterName; 
    numChapters = numChapters + 1;
  } 

// Needs more help
public String
  getChapter(int chapterNum) 
throws Exception { chapterNum=chapterNum - 
1; if (chapterNum >= numChapters) 
{ throw new Exception(); } if
(chapterNum < 0) { throw new Exception(); }
  if
(chapters[chapterNum] == null)            {
  throw new Exception();                  }
  return chapters[chapterNum]; } }


You may find it helpful to use the following test program.


import SimpleOutput;

/**
 * Test our sample book class.  Does not yet test all issues
 * (such as zero-parameter constructors).
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of September 1999
 */
public class BookTester {
  public static void main(String[] args) 
    throws Exception
  {
    SimpleOutput out = new SimpleOutput();
    Book eij = new Book("Sam Rebelsky", "Experiments in Java");
    // Print the basic information.
    out.println("* Test: Print basic information");
    out.print(eij.toString());
    // Set two chapters.
    out.println("\n*Test: Set two chapters");
    eij.addChapter("J1: An Introduction to Java");
    eij.addChapter("J2: Objects and Classes");
    out.print(eij.toString());
    // Get an valid chapter.
    out.println("\n*Test: Get valid chapter");
    out.println("Chapter 2: " + eij.getChapter(2));
    // Get an invalid chapter.
    out.println("\n*Test: Get invalid chapter");
    try {
      out.println("Chapter 4: " + eij.getChapter(4));
    }
    catch (Exception e) {
      out.println("As expected, that failed.");
    }
    // Add too many chapters
    out.println();
    for (int i = eij.getNumChapters(); i < 25; ++i) {
      try {
        out.print("*Test: Adding chapter " + i + "...");
        eij.addChapter("Untitled");
        out.println("okay");
      }
      catch (Exception e) {
        out.println("failed");
      } // caught "too many chapters" exception
    } // add a lot of chapters
    // And see what we have
    out.println("\n*Final version:");
    out.println(eij.toString());
  } // main(String[])
} // class BookTester


A Solution

Here's the solution that I came up with. Yours may be more detailed.


/**
 * A simple, <Q>write-once</Q> representation of books.  Once the
 * author, title, and chapters are in place, they cannot be easily
 * changed (except by directly accessing the fields).
 * Note that rather than supporting a
 *   setChapter(int n, String * chapterName)
 * method, which some clients might misuse by setting the 5th chapter
 * but not the prior chapters, we have decided to limit clients to
 * adding chapters to the end of the book.  This lets client build but
 * not change the table of contents.
 *
 * The maximum number of chapters is 20.  This is a bad design.  It
 * would be better to allow the consturctor to take the number of
 * potential chapters as a parember.
 *
 * @author Carl Caffeinated
 * @author Carla Ceffeinated
 * @author Samuel A. Rebelsky
 * @version 1.0 of 24 September 1999
 */
public class Book {

  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** The title of work. */
  protected String title;

  /** The author of the book. */
  protected String author;

  /**
   * The number of chapters currently stored in the work.
   * Note that this is always 1 higher than the index of
   * the highest-numbered chapter in the chapters array.
   */
  protected int numChapters;

  /**
   * The chapters of the book (or, more precisely, the names of
   * the chapters of the book.
   */
  protected String[] chapters;

  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /** Create a new book that supports up to twenty chapters. */
  public Book() {
    this.chapters = new String[20];
    this.numChapters = 0;
  } // Book()

  /** Create a new book that supports up to numChapters chapters. */
  public Book(int numChapters) {
    this.chapters = new String[numChapters];
    this.numChapters = 0;
  } // Book(int)

  /**
   * Create a new book with a specified author and title and up
   * to twenty chapters.
   */
  public Book(String author, String title) {
    this.author = author;
    this.title = title;
    this.chapters = new String[20];
    this.numChapters = 0;
  } // Book(String,String)

  // +-----------+-----------------------------------------------
  // | Accessors |
  // +-----------+

  /** Get the author of the book. */
  public String getAuthor() {
    return this.author;
  }  // getAuthor()

  /**
   * Get the title of chapter chapterNum.
   *
   * @exception Exception
   *   If there is no such chapter.
   */
  public String getChapter(int chapterNum)
    throws Exception
  {
    // Move from "human" indexing (starting at 1) to Java
    // indexing (starting at 0).
    chapterNum=chapterNum - 1;
    // Verify that the chapter number is valid.
    // a. It must be <= numChapters-1.  See above for more info.
    if (chapterNum >= numChapters) {
     throw new Exception();
    } // if it's too large
    // b. It must be >= 0 since the array indices start with 0.
    if (chapterNum < 0) {
      throw new Exception();
    } // if it's too small
    // c. The chapter must be there.  This test is not strictly
    // necessary, as we've carefully worked to ensure that the
    // chapters between 0 and numChapter-1 (Java numbering) are
    // all defined.  However, we may later change that decision
    // and it seems safest to be prepared for all situations.
    if (chapters[chapterNum] == null) {
      throw new Exception();
    }
    // That's it, just return the correct element.
    return chapters[chapterNum];
  } // getChapter(int)

  /** Determine the number of chapters in the book. */
  public int getNumChapters() {
    return this.numChapters;
  } // getNumChapters()

  /** Get the title of the book. */
  public String getTitle() {
    return this.title;
  } // getTitle()

  /** Convert the book to a string in preparation for printing. */
  public String toString()
  {
    // Add the author and title.  The title is in quotes.
    // Coding note: in Java, \" is how you get a quote in the
    // middle of a string.
    String stuff = "\"" + this.title + "\" by " + this.author + "\n";
    // Step through the chapters, adding each as you go.  Since
    // most people start their numbering at 1 rather than 0, we
    // add 1 to the index into the chapters array.
    for (int i = 0; i < numChapters; ++i) {
      if (chapters[i] != null) {
        stuff = stuff + "  " + (i+1) + ": " + chapters[i] + "\n";
      } // if the chapter is not null
    } // for
    // That's it, we're done.
    return stuff;
  }  // toString()


  // +-----------+-----------------------------------------------
  // | Modifiers |
  // +-----------+

  /**
   * Add a new chapter to the end of the table of contents.
   * See introductory notes for the rationale behind this.
   *
   * @exception Exception
   *   If there's not room for another chapter.
   */
  public void addChapter(String chapterName)
    throws Exception
  {
    // If there is not room for another chapter, throw an exception.
    if (numChapters >= chapters.length) {
      throw new Exception();
    }
    // Add the chapter.
    //   Coding note: Since we start indexing the array at 0, the
    //   number of chapters is 1 higher than the largest index used
    //   so far.  Hence, we can use it as the index of the first free
    //   element.
    chapters[numChapters] = chapterName;
    // Move on to the next chapter.
    numChapters = numChapters + 1;
  } // addChapter(String)

} // class Book


Some Notes

The designers of this class had a particularly interesting design strategy with regards to chapters. That is, rather than allowing clients to change chapter titles, they only allow authors to add chapter titles. It might be useful to document the possible motivatoin for such a design.

It's fairly obvious when things are fields and methods. So, in your introductory comment you don't need to say ``A class that ...'', ``A field for ...'', or a ``A method that ...''. I didn't take off for this, but expect you to be more careful about it in the future.

A few of you claimed that toString ``prints'' something. It doesn't. It generates a string that might later be printed (or written to a file, or modified, or ...).

Two of the constructors limited the number of chapters in the book to twenty. It is necessary to document such limits. If you didn't, I took off 2 points.

Two of the methods (getChapter and addChapter) had some fairly confusing code. If you didn't comment that code, I took off 5 points.

Both of those methods threw exceptions. If you didn't indicate when the method threw an exception, I took off 2 points.

You updated the code and therefore belong as an author. If you didn't include your name, I took off 1 point.

As I've mentioned many times, it's important that you comment end braces. If you didn't, I took off 3 points.

There's a weird "\"" in the code. You should have tried to explain it. If you didn't, I didn't take off anything, since that was particularly confusing.

History

Friday, 24 September 1999

Monday, 27 September 1999

Wednesday, 29 September 1999


Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

This page may be found at http://www.math.grin.edu/~rebelsky/Courses/CS152/99F/Exams/examsoln.01.html

Source text last modified Wed Sep 29 08:44:30 1999.

This page generated on Sun Oct 17 20:55:59 1999 by Siteweaver. Validate this page's HTML.

Contact our webmaster at rebelsky@grinnell.edu