CS46A Lab

Input/Output

Copyright © Cay S. Horstmann 2009 Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.

In this lab, you will work in groups of four for the planning part (A) and in groups of two for the implementation parts (B and C)

Put the answers to the questions in each step into the lab report. Copy/paste the programs that you write in the lab.

This icon indicates optional tasks. Do those if you have time.

Part A: Taxes and Inflation

Roles:

A) The scribe who writes the pseudocode and the lab report

B) The code reader who reads the pseudocode aloud during simulation and updates any variables

C) The scanner who simulates a java.util.Scanner

D) The facilitator who makes sure everyone does their thing

  1. Turn your browser to http://www.truthandpolitics.org/top-rates.php. You'll see a large table with tax rates. At first glance, it's just a bunch of numbers, but if you look at it closely, is actually a politically rather explosive table. Look at the years 1953-1961 in which Eisenhower was president—any income you made over $400,000 was taxed at 91%. Was this man a Godless Communist? Or maybe it explains why in those times, this country was able to build roads, airports, and universities, instead of watching them crumble?

    Let's look at these numbers a little more closely. Suppose you made $400,000 per year and then got a much-deserved bonus of another $100,000. How much of that bonus were you able to keep after federal taxes in 1961? In 2003?

  2. Of course, $400,000 in 1961 was quite a bit more than it is today, so we should really translate all those numbers into 2008 dollars for a fair interpretation. Go to http://www.bls.gov/cpi/tables.htm and click on “Table Containing History of CPI-U U.S. All Items Indexes and Annual Percent Changes From 1913 to Present”. Or simply click on ftp://ftp.bls.gov/pub/special.requests/cpi/cpiai.txt. If FTP doesn't work for you, use the page that I mirrored here.

    Note that this data is in plain text, without any fancy fonts or images. Plain text may be ugly, but it is easy to process.

    Look at the data. If necessary, resize the window so that the lines don't wrap. Notice that there are 18 header lines, then a line for 1913 with 14 numbers (that lacks the percentage changes in the last two columns), then lots of lines with 16 numbers each, then the line for the current year which isn't complete.

    We can ignore the month-to-month changes. All we care about is the Annual Average in column 14. The numbers are relative to the average of 1982-1984, which is 100%.

    In order to translate dollar amounts from one year to another, divide by the "from year" CPI and multiply with the "to year" CPI.

    How much is 1961's $100,000 in 2003?

  3. Now we want to solve our task more systematically. Your job is to formulate pseudocode for the various subtasks.

    We will start with reading the CPI data (i.e. the second data set).

    In Chapter 11, you learn how to attach a Scanner to a file or a URL on the internet.

    Remember that a Scanner can read in an entire line with nextLine or an item at a time with next, nextInt, or nextDouble.

    Write pseudocode that reads the data from ftp://ftp.bls.gov/pub/special.requests/cpi/cpiai.txt and fills an array with the CPI values. Put the value for year y into cpi[y - 1913]

    Address the following issues:

    Your result should be a sheet of paper with pseudocode (which the scribe should add to the lab report).

  4. Simulate the pseudocode. The code reader reads an instruction. If that instruction involves the scanner, the code reader asks the scanner to supply the answer. The scanner crosses out the input that has been consumed (on a printout of the data that the lab assistant should have supplied). (Alternatively, apply white-out on your laptop screen.)

    Run the simulation until 1916 (to catch that blank line), then skip ahead to the current year line.

    Which elements have been filled into which locations of the cpi array as result of your simulation?

  5. Now on to the table of tax rates. Unfortunately, this table is not in plain text but in HTML. To see what the Scanner sees when reading this data, use the "View Source" command of your browser. What do you notice?
  6. Yikes, that's a lot of HTML code. Fortunately, the table that we want is fairly regular. Scroll down until you see
    <tr><td align="center">1913</td><td align="center">7</td><td>&nbsp;</td><td align="center">500,000</td></tr>
    <tr><td align="center">1914</td><td align="center">7</td><td>&nbsp;</td><td align="center">500,000</td></tr>
    <tr><td align="center">1915</td><td align="center">7</td><td>&nbsp;</td><td align="center">500,000</td></tr>
    <tr><td align="center">1916</td><td align="center">15</td><td>&nbsp;</td><td align="center">2,000,000</td></tr>
     ...

    Let's break down our task of reading these data into three subtasks:

    The line for 1913 that you will print should look like this:

    1913    7  10873889

    (10873889 is 500000 * 215.303 / 9.9)

    What line should you print for 1944?

  7. Let's read all lines of the input with nextLine. Describe which ones you should analyze further.
  8. Now suppose we have a line
    <tr><td align="center">1914</td><td align="center">7</td><td>&nbsp;</td><td align="center">500,000</td></tr>

    As you may know, the <td...>...</td> enclose table cells. A worthwhile subtask is to write a method

    ArrayList<String> extractTableCells(String row)

    For example, with the sample input above, the result will be an ArrayList<String> with entries

    "1914"
    "7"
    "&nbsp;"
    "500,000"

    This isn't really related to I/O and exceptions, so we won't spend time in this lab developing this method. It will just be given to you. But to show that you have an understanding how it works, put in your lab report what the method should return for the input line of 1944.

  9. Note that you now have String objects. You don't want strings. You want numbers. Discuss how you will convert the strings to numbers. Discuss what challenges you will encounter. (Hint: "500,000". The footnotes that you saw in the preceding step.) How will you get rid of those commas? (Hint: Blast from the past—section 2.4 of your textbook).
  10. Now write pseudocode for processing the tax rates data.
  11. Test your pseudocode. Quickly skip to the interesting part of the data set and run through a couple of characteristic input lines, such as 1914 and 1944. The person playing the “scanner” role should also announce the return values of the calls to extractTableCells.

    The scribe reports the results of the walkthrough.

Part B. Implementation

You do this part in groups of 2, using the strategies that you developed in part A.

  1. Start Netbeans (not BlueJ). Select File -> New Project -> Java -> Java Application. Click Next. Set the name to iolab. Click Finish. A class Main has been provided for you in the iolab package. That's a good default. But we want to make a class CPIConverter that deals with reading the CPI data and converting dollar amounts from one year to another. Select the iolab package. Right-click on the iolab package (not the project) and select New -> Java Class, then CPIConverter.

    Add methods

    public void read(String location) 
    {
    }
    
    public double equivalentAmount(double amount, int fromYear, int toYear) 
    {
       return amount; // We'll fix this later
    }

    Add an instance variable

    private double[] cpi;

    Add constants

    private static final int FIRST_YEAR = 1913;
    private static final int LAST_YEAR = 2008;
  2. Let's implement the read method. First initialize cpi with an array that can hold LAST_YEAR - FIRST_YEAR + 1 values. (Why +1?)

    The book tells you how to construct a scanner from a FileReader. But we are not reading from a file. We read from the web, as you would expect us to do in the third millennium. Here is how you do that in Java:

    Create a URL object

    URL cpiURL = new URL(location);
    InputStream cpiIn = cpiURL.openStream();

    Then, instead of constructing a scanner from a FileReader, construct it from the cpiIn object.

    As you type names such as URL and InputStream, get in the habit of typing Ctrl+Space towards the end of the name. Netbeans will insert the remainder of the name for you, and more importantly, add the import statement.

    If you copy/paste the code, just move the cursor to the end of URL and InputStream, then hit Ctrl+Space.

    Try it out now!

  3. Now look to the left of these two lines. You should see a couple of lightbulb icons.

    That means that the IDE found an error with the code. Click on the lightbulb to get “quick fix” suggestions. The quick fix that we want is to add a throws specifier. (Do not add a try/catch block. We will handle the exceptions elsewhere.)

    Try it out. Let the IDE add the exceptions. Click on the first light bulb and choose throws..., then on the second. The light bulbs should go away. What code was added?

  4. Is this cheating? Not really—you still need to know what the right choice is. The IDE can't decide for you which syntax to use. It just applies your choice without making a typing error.

    In fact, IDEs are not perfect. Look up the documentation of MalformedURLException. Note its superclasses. Note the other class that Netbeans added to the throws specifier. How can you simplify the throws specifier?

  5. We'll start reading a simpler data set at http://horstmann.com/sjsu/cs46a/lab12/cpiai2.txt. Look at the data set and write the read method to process it. What is the code of your read method?
  6. Complete the equivalentAmount method. Use cpi[fromYear - FIRST_YEAR] and cpi[toYear - FIRST_YEAR] to adjust the amount. What is the code of your method?
  7. Now go on to the Main class that Netbeans made for you. In its main method, add
    CPIConverter conv = new CPIConverter();
    conv.read("http://horstmann.com/sjsu/cs46a/lab12/cpiai2.txt");
    double amount = 100000;
    double adjusted = conv.equivalentAmount(amount, 1962, 2008);
    System.out.printf("Adjusted amount: %10.0f\n", adjusted);

    You will get another lightbulb. Why?

  8. For now, have main throw the exception. We'll fix that later. Now run your program. What value do you get? Is it the same as in step A2?
  9. In Netbeans, click on the left margin of the first line of code inside the read method. A red box should appear, indicating a breakpoint.

    From the menu, choose Debug -> Debug Main Project. When the debugger stops at the line, click on the Variables tab below.

    Expand the this variable until you see the cpi instance variable. What is its value?

  10. Locate the Step Over button and click it.

    What is the cpi contents now?

  11. Expand the cpi variable. What do you see? Why?
  12. Set another breakpoint at the end of the loop that reads one line. Click the Continue button a few times. (Mouse over the buttons to find it.)

    Each click, one iteration of the loop is executed. What happens with the cpi contents?

  13. Remove the breakpoints (by clicking on them) and click Continue. What happens?
  14. Fix the read method to implement the strategy that you developed in step A3. Change main so that it reads from ftp://ftp.bls.gov/pub/special.requests/cpi/cpiai.txt. Run your program to check that it works.

    What is the code of your read method now?

C. Handling exceptions

  1. Change the argument of the read method in main to http://www.cs.sjsu.edu/foo.html. Run the program. What happens?
  2. It is rather unsightly to leave the exceptions unhandled. We want to catch them somewhere and tell the user that a problem occurred.

    In which method should they be caught, read or main?

  3. Catch the IOException and print a suitable message to the user. What is the code of your modified method?
  4. Run the program again. What happens?
  5. It would be nice to give different error messages for a MalformedURLException than a garden variety IOException. Change your method so that it prints “Whoa! Your URL was malformed.” or “To our chagrin, an IOException has occurred.” Also print the message stored in the exception object. What is the code of your modified method?
  6. Run the program again. What happens?
  7. Now change the URL to foo://bar.html. Run the program again. What happens?

D. Completing the Program

  1. In Netbeans, make a new class TaxData. Add these instance variables:
    public class TaxData
    {
       private int year;
       private double topMarginalRate;
       private double topMarginalThreshold;
    
    }

    Move the cursor above the } and hit Ctrl-Space. You'll get a window such as this one.

    Select the second constructor public TaxData(int year, double topMarginalRate, double topMarginalThreshold) and hit Enter. What happens?

  2. Eat your heart out, BlueJ! Repeat with getYear, getTopMarginalRate, and getTopMarginalThreshold. What happens?
  3. Add a class TaxTableReader
    public class TaxTableReader
    {
       public void read(String location) throws IOException
       {
       }
    
       public void print(CPIConverter conv, int year)
       {
       }
    
       private ArrayList<String> extractTableCells(String row)
       {
          ArrayList<String> result = new ArrayList<String>();
          int pos = 0;
          boolean done = false;
          while (!done)
          {
             pos = row.indexOf("<td", pos);
             if (pos == -1) done = true;
             else
             {
                pos = row.indexOf(">", pos);
                int start = pos + 1;
                pos = row.indexOf("</td>", pos);
                result.add(row.substring(start, pos));
             }
          }
          return result;
       }
    
       private ArrayList<TaxData> data;
    }

    Now write the read method.

    What is the code of your read method?

  4. In main, add code to make a TaxTableReader and read from http://www.truthandpolitics.org/top-rates.php. Compile and run. If your program doesn't throw any exceptions, go on to the next step.
  5. Let's print the data nicely, like this:
    1913    7.0 10,873,889
    1914    7.0 10,765,150
    1915    7.0 10,658,564
    1916   15.0 39,505,138
     ...

    Use the converter to convert the thresholds to the given year.

    To add those commas, add a comma to the printf descriptor: %,10.0f.

    What is the code of your print method?

  6. In main, call print and run your program. What is the output?
  7. Look at the numbers. These are now in 2008 dollars. When did the rich get soaked? When did they have it best? For added fun, check out who was president in each of those periods.
  8. Change the print method so that the output is sent to a file:
    public void print(String filename, CPIConverter conv, int year) throws IOException