Copyright © Cay S. Horstmann 2009 - 2015
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
Modified by:
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?
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:
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:
Scanner
method(s) will you call to read and discard the header information? How many calls?Scanner
method(s) will you use to read each line? Which values do you use? Which do you discard? What do you do with the values that you use? (I.e. where do you put them)?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?
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
<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) :
<head> <!-- Contain website INFO: Title, layout, javascript, etc... --> </head> <body> <!-- Website contents --> </body> </html>
<table> ... <tr><td align="center">1913</td><td align="center">7</td><td> </td><td align="center">500,000</td></tr> <tr><td align="center">1914</td><td align="center">7</td><td> </td><td align="center">500,000</td></tr> <tr><td align="center">1915</td><td align="center">7</td><td> </td><td align="center">500,000</td></tr> <tr><td align="center">1916</td><td align="center">15</td><td> </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?
nextLine
. Describe which ones you should analyze further.<tr><td align="center">1914</td><td align="center">7</td><td> </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" " " "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?
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).Scanner
calls do you make?extractTableCells
)?extractTableCells
will give you an ArrayList of four elements. What do you do with each ArrayList element to extract the number that may be inside it. (Hint: see section 11.2.6)cpi
array has been correctly initialized in step 3.extractTableCells
.
The scribe reports the results of the walkthrough.
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.)
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!
That means that the IDE found an error with the code. (A ! on the lightbulb 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?
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)
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?
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.
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?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.
Expand the this
variable until you see the cpi
instance variable. What is its value?
What is the cpi
contents now?
cpi
variable.
What do you see? Why?
Each click, one iteration of the loop is executed.
What happens with the cpi
contents?
What happens?
To leave the debug perspective and return the the normal view, Select Window → Open Perspective → Java
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.
read
method in main
to http://www.cs.sjsu.edu/foo.html
. Run the program.
What happens?
In which method should they be caught, read
or main
?
IOException
and print a suitable message to the user. What is the code of your modified method?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?foo://bar.html
. Run the program again. What happens?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)
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.
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.
location
a line at a time, and only process the lines in the table.
while (in.hasNextLine()) { String line = in.nextLine(); if (line.startsWith("<tr><td align=\"center\">")) { ... } }
(Note the \"
because we are looking for a string containing quotation marks: <tr><td align="center">
)
extractTableCells
. DO NOT MODIFY THIS METHOD.indexOf(" ")
. Have a look at extractTableCells
if you want to see indexOf
in action.)int
and two double
TaxData
object and add it to the dataWhat 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.
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.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?
main
, call print
and run your program. What is the output?print
method so that the output is sent to a file:
public void print(String filename, CPIConverter conv, int year) throws IOException