Computer Science 252
Problem Solving with Java
Spring 2016, The College of Saint Rose
This is the second of the three "review" labs that are designed to refresh and sharpen your prerequisite Java programming skills. Again, there are a few programs to write, but all are things you should be comfortable doing, maybe with a little refreshing of your memory, having completed the prerequisites successfully.
You are to work individually on these tasks. Searching for similar programs on the Internet (or anywhere) is not permitted, and would be counterproductive to your ability to learn how to approach these straightforward tasks. However, you should feel free to ask your instructor, our graduate assistant, or the ASC tutors for help as you work through them.
This second review lab focuses on file input/output and exception handling. All programs for this lab are once again Java applications and all have been designated as practice programs.
Getting Set Up
To get your BlueJ environment set up for this week's lab assignment, start BlueJ and choose "New Project" from the "Project" menu. Navigate to your folder for this course and choose the name "Lab2" (no spaces) for the project.
Practice Programs: File Input and Exception Handling
Once you're comfortable with console I/O, using files for input and output in Java is just a matter of remembering to do a few more steps. There are multiple ways of doing this in Java, and you are welcome to use any. But this lab will focus on the use of the Scanner for input and the PrintWriter for output.
Suppose you have a file called "myfile.txt" in your folder with your Java program. (In BlueJ, this is the folder that has the .java, .class, and a few other files.) You can construct a Scanner to read the contents of the file and remember the Scanner in a local variable with the following line of code:
Scanner infile = new Scanner(new File("myfile.txt"));
Note that you will also need to add an import statement:
import java.io.File;
We'll get into the things you can do with the Scanner below, but for now, we also should put in code that closes the Scanner:
infile.close();
Any code that reads from infile goes in between the above statements.
Exception Handling
You will also need to deal with the fact that this is an operation that might go wrong. The file you're trying to read might not exist. Or you might not have sufficient privileges to read it. In that case, Java's exception handling mechanism comes into play. We can choose to ignore (almost, anyway) the exceptions in which case your program would just crash with a messy traceback, or we can "catch" them and handle them. If you ignore them, the simplest thing to do is to add a qualifier to the end of your main method's signature:
public static void main(String args[]) throws IOException
with the corresponding import:
import java.io.IOException;
This has the advantage that once you've done it, you can use all of the File I/O classes and methods in your main method without worrying about exceptions. If one occurs, your main method will "throw" it back to the Java run-time system, which will then kill your program and print the stack trace. Disadvantages of this approach include (i) only your main method, or others with the "throws" qualifier, will be able to use I/O classes and methods, (ii) your program will crash with an ugly message if any exceptions are thrown.
If we have our programs "catch" and handle the exceptions, we can control how those error situations affect our program.
The code would look something like this, called a try-catch block:
try { // do file I/O things } catch (IOException e) { // do something about the error described // in the Exception called e }
In this case, we could go back and retry (maybe after prompting for a new file name) or print a message and quit anyway. Something like:
try { Scanner infile = new Scanner(new File("myfile.txt")); // other things with "infile" infile.close(); } catch (IOException e) { System.err.println(e); System.exit(1); }
This will print a human-readable message that explains the exception and then exits.
Reading from the Scanner
Of course, in real programs, you are usually interested in the contents of the file. Fortunately, you use the same methods as you'd use with a keyboard Scanner. You can read the next instance of a particular data type with the next, nextLine, nextInt, etc.., methods, and can check for their existence with the hasNext, hasNextLine, hasNextInt, etc.., methods. For example, to read all integer numbers from a file "numbers.txt" and add them up, this code fragment could be used (exception handling omitted):
Scanner numbers = new Scanner(new File("numbers.txt")); int sum = 0; while (numbers.hasNextInt()) { int n = numbers.nextInt(); sum += n; } numbers.close(); System.out.println("Sum is " + sum);
Important side notes about plain text files! Hopefully if you've gotten this far, you understand the difference between a plain text file like your Java program text, and formatted files like Word documents or PDFs. Here, we are dealing strictly with plain text files. For better or for worse, modern operating systems (Windows, Mac OS X) try their best to stop users from dealing with plain text. Many programs store files in more complicated formats unnecessarily, and the systems often hide file extensions from you. Please don't hesitate to ask if you have trouble creating and editing plain text files.
Note that your program should only count numbers that are readable with Scanner's nextDouble method. So a number embedded within a word or with punctuation at the end will not be counted. Consider this sample input file:
4 Little Pr1mes: 2 3 5 7! But are 2.5 and 10.75 prime? -1?
My program prints:
Sum is 27.25
which is the sum of the 4, 2, 3, 5, 2.5, and 10.75. The embedded "1" and the ones at the end of the lines with punctuation at the end are not readable as double values by the Scanner, so are ignored as non-numeric text.
Practice Program: File Output
File output is also analogous to console I/O. Rather than calling methods of System.out (most commonly print and println), we construct and call methods on a PrintWriter object.
Java API Documentation: java.io.PrintWriter
This code segment will create a plain text file with the first line of a famous book (exception handling omitted):
PrintWriter outfile = new PrintWriter(new File("ss.txt")); outfile.println("Mr. and Mrs. Dursley of Number Four, Privet Drive,"); outfile.println("were proud to say that they were perfectly normal,"); outfile.println("thank you very much."); outfile.close();
As you can see, once a PrintWriter is constructed and a reference to it is remembered in a variable, that variable can be used like "System.out" is used for console output. Really, that's all there is to it!
Practice Program: Combining Input and Output
For my version of the program, if the input file contains the text:
I-90 7 3.75 30 8.7 I-87 4 104.3 US20 0.5 87.2 5.4 29.3
then the output file would contain:
I-90: 49.45 I-87: 108.3 US20: 122.4 Grand total: 280.15
Note that formatting is not important in the input file. That is, all of the names and numbers could be broken into any number of lines. For example, I-90's entry could be all on a single line:
I-90 7 3.75 30 8.7
Fortunately, if you use the Scanner's methods correctly, the program does not need to know or care exactly how the input file is formatted.
Note: you can and should assume that road names begin with a letter and contain no spaces. Hint: this means you can read them in their entirety with the Scanner's next method.
Submitting
Before 11:59 PM, Thursday, February 4, 2016, submit your lab for grading. To complete the submission, email a copy of your lab (a .7z or .zip file containing your project directory) to terescoj AT strose.edu.
Grading
This assignment is worth 35 points, which are distributed as follows:
> Feature | Value | Score |
OpenFiles correctness | 5 | |
ReadAllDoubles correctness | 10 | |
Odds correctness | 5 | |
TravelLog correctness | 15 | |
Total | 35 | |