CS46B Lab 4

Input/Output

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

Modified by:

Instructions

Working in Pairs

Part A: Taxes and Inflation (DO NOT TOUCH ECLIPSE UNTIL YOU FINISH THIS PART)

  1. Turn your browser to this link (http://web.archive.org/web/20110429200904/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 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 2003 dollars for a fair interpretation.
    If you want to know where to look for data, go to http://www.bls.gov/cpi/tables.htm and click on "CPI Detailed Report (complete text and tables) December 2014". It's a PDF file, and the table we are taking about is table 24. However, at this point, you are not at the level of developing an app to read data from the PDF file. Now close that window/tab.

    Look at this file (http://cs46labs.bitbucket.org/cs46b/lab3/cpiai1.txt). This is an older version of the page from bls.gov in plain text.

    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 (some of them are blank 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 may or may not be complete, depending on when you check the page.

    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 by the "to year" CPI.

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

    Doing this same calculation for $1.00, you will see that something that cost $1 in 1961 would, on average, cost about $6 in 2003.

    Below is a snapshot of the cpiai1 file:

    cpiai_format

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

    OK. Now let's start with class Scanner. You have used Scanner to read input from the keyboard. It can also be used to read from a file. If you don't know how the Scanner class is used to read a file, PAUSE!!!!!

    Look up! Look to the Left! Look to the Right! Look Behind! If your TA is in 1 of those 4 directions, request your TA to explain Scanner usage if he/she has not done so, or you can Google for examples.

    A Scanner instance can help you read/load in an entire line into your application buffer with nextLine or an item at a time with next, nextInt, or nextDouble.

    Simulate pseudocode that reads the data from capiti1.txt and fills an array with the CPI values. Put the value for year y into cpi[y - 1913] (Use if for your lab and turn it inot your lab instructor. Be sure to put both the scribe and the driver's name on the paper)

    Address the following issues:

  4. Trace the pseudocode. The scribe reads an instruction. If that instruction involves the scanner, the driver 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.

    Trace the pseudocode 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 that you saw in step 1 (A1). Unfortunately, this table is not in plain text but in HTML format. To see what the Scanner sees when reading this data, use the "View Source" command of your browser. What do you notice?

    Right click and select the command to view the page source. It is different on different browsers but will be something like View Page Source or Show Source

  6. Yikes, that's a lot of HTML code. In short, the structure of a HTML page is below:
    <html>
    <head> <!-- Contain website INFO: Title, layout, javascript, etc... --> </head> <body> <!-- Website contents --> </body> </html>
    Fortunately, the table that we want is fairly regular. Scroll down in the <body></body> until you see the following (or use find to find the 6th table) :
    <table>
     ...
    <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>
     ...
    </table>
    

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

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

    1913    7  9292929.3

    (9292929.3 is 500000 * 184.0 / 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:

    What should the method 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.3 of your textbook).
  10. Now write pseudocode for processing the tax rates data.
  11. Test your pseudocode. The driver simulates the computer. The scribe reads the statements. Quickly skip to the interesting part of the data set and run through a couple of characteristic input lines, such as 1914 and 1944. Also announce the return values of the calls to extractTableCells.

    The scribe reports the results of the walkthrough.

Part B. Implementation

  1. Start Eclipse. Create a new project with name lab3. We want to make a class CPIConverter that deals with reading the CPI data and converting dollar amounts from one year to another. Right-click on src (not the project name) and select New -> Class, name your new class as 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 = 2003;
    (2003 is the last line of the tax rate table in the file above, even if we have current cpi data in the CPI Detailed Data table.)
  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. Remember to add the second parameter of "UTF-8"

    Scanner in = new Scanner(cpiIn, "UTF-8");

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

    If you copy/paste the code, you will see a red dashed line under a class name Put your cursor over the class name and select Import ... from the drop down menu.

    Try it out now!

  3. Now look to the left of these two lines. You should see a couple of lightbulb icons with red x's error icon. (The image below is from Eclipse)

    That means that the IDE found an error with the code. (A ! on the lightbulb warning icon indicates a warning.) Click on the lightbulb to get “quick fix” suggestions. The quick fix that we want is to add a throws declaration. (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.
  5. We'll start reading a simpler data set at http://sjsucs.bitbucket.org/cs46b/lab3/cpiai2.txt. Yes, we actually practice reading a file using the simplest input version first- this is lets us concentrate on one part of the program at a time.

    Look at the data set and implement the read method to process it.

    What is the code of your read method? (Your code is, of course, in an incomplete state for now)

  6. Complete the equivalentAmount method. Use cpi[fromYear - FIRST_YEAR] and cpi[toYear - FIRST_YEAR] to adjust the amount. (Remember: In order to translate dollar amounts from one year to another, divide by the "from year" CPI and multiply by the "to year" CPI.)

    What is the code of your method?

  7. Add a tester class to the default package. In its main method, add
    CPIConverter conv = new CPIConverter();
    conv.read("http://sjsucs.bitbucket.org/cs46b/lab3/cpiai2.txt");
    double amount = 100000;
    double adjusted = conv.equivalentAmount(amount, 1961, 2003);
    System.out.printf("Adjusted amount: %10.0f\n", adjusted);

    You will get another error lightbulb.

    Why? How do you fix it?

    Notice that when in the window for creating the class, there is a checkbox that will add a main method for you. Just another little time saver.

  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. Let's look at the debugging tool. (We will learn this tool in detail in later labs.)
    In Eclipse, click (or double click) on the left margin of the first line of code inside the read method. A blue circle should appear, indicating a breakpoint.

    From the menu, choose Run -> Debug (or Ctrl+F11). Click "Yes" in the dialog box. When the debugger stops at the line, click on the Variables tab in the right panel at the top.

    variable tab

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

    What happens?

    To leave the debug perspective and return the the normal view, Select Window → Open Perspective → Java

  14. optionalFix the read method to implement the strategy that you developed in step A3. Change main so that it reads from http://sjsucs.bitbucket.org/cs46b/lab3/cpiai1.txt. Run your program to check that it works.

    What is the code of your read method now?

    Remember you must complete the optional parts before you can leave early. I recommend skipping this for now and coming back to it after you finish the remaining parts.

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 (and unhelpful to the user) to leave the exceptions unhandled like that. We want to catch them somewhere and tell the user that a problem occurred. That is what professionals do.

    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. optionalIt 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. optionalRun the program again. What happens?
  7. optionalNow change the URL to foo://bar.html. Run the program again. What happens?

D. Completing the Program

  1. In Eclipse, 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. (The image below is a snippet from Netbeans, and Eclipse does behaves in the same manner)

    complition menu

    This will let you easily add a constructor and basic methods. Unfortunately, it will only add the default constructor, and we need constructor that takes the three instance variables. Add this constructor public TaxData(int year, double topMarginalRate, double topMarginalThreshold)

    Now move the cursor above the } and hit Ctrl-Space again. Scroll down, select getYear, and hit Enter. Repeat with getTopMarginalRate, and getTopMarginalThreshold. What happens?

    Eat your heart out, BlueJ! Remember class Item in Lab 1 and how tedious it was to add all the getters and setters? Just another time saver from your friends at Eclipse.

  2. optionalAdd 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?

    If your program throw Exceptions, that's OK! Setup a breakpoint within the while loop and identify the cause of the thrown Exception.

  3. optionalIn main, add code to make a TaxTableReader and read from http://web.archive.org/web/20110429200904/http://www.truthandpolitics.org/top-rates.php. Compile and run. If your program doesn't throw any exceptions, go on to the next step.
  4. optionalLet'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?

  5. optionalIn main, call print and run your program. What is the output?
  6. optionalLook at the numbers. These are now in 2003 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.
  7. optionalChange the print method so that the output is sent to a file:
    public void print(String filename, CPIConverter conv, int year) throws IOException