You must close a file when you are done processing it:
out.close();
Otherwise, not all of the output may be written to the disk file
FileNotFoundException
When the input or output file doesn't exist, a FileNotFoundException can occur
To handle the exception, label the main method like this:
public static void main(String[] args) throws FileNotFoundException
A Sample Program
Reads all lines of a file and sends them to the output file, preceded by line
numbers
Sample input file:
Mary had a little lamb
Whose fleece was white as snow.
And everywhere that Mary went,
The lamb was sure to go!
Program produces the output file:
/* 1 */ Mary had a little lamb
/* 2 */ Whose fleece was white as snow.
/* 3 */ And everywhere that Mary went,
/* 4 */ The lamb was sure to go!
Program can be used for numbering Java source files
ch11/lines/LineNumberer.java
Self Check 11.1
What happens when you supply the same name for the input and output files to the LineNumberer
program?
Answer:
When the PrintWriter object is created, the output file is emptied.
Sadly, that is the same file as the input file. The input file is now empty and
the while loop exits immediately.
Self Check 11.2
What happens when you supply the name of a nonexistent input file to the LineNumberer
program?
Answer:
The program catches a FileNotFoundException, prints an error message,
and terminates.
File Dialog Boxes
JFileChooser chooser = new JFileChooser();
FileReader in = null;
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
{
File selectedFile = chooser.getSelectedFile();
reader = new FileReader(selectedFile);
. . .
}
Reading Text Input: Reading Words
The next method reads a word at a time:
while (in.hasNext())
{
String input = in.next();
System.out.println(input);
}
With our sample input, the output is:
Mary
had
a
little
lamb
...
A word is any sequence of characters that is not white space
Reading Text Input: Reading Words
To specify a pattern for word boundaries, call Scanner.useDelimiter
Example: discard anything that isn't a letter:
Scanner in = new Scanner(. . .);
in.useDelimiter("[^A-Za-z]+");
...
The notation used for describing the character pattern is called a regular expression
Reading Text Input: Processing Lines
The nextLine method reads aline of input and consumes the newline character at the end of the line:
String line = in.nextLine();
Example: process a file with population data from the CIA Fact Book with lines like this:
China 1330044605
India 1147995898
United States 303824646
...
First read each input line into a string
Then use the isDigit and isWhitespace
methods to find out where the name ends and the number starts. E.g. locate the first digit:
int i = 0;
while (!Character.isDigit(line.charAt(i))) { i++; }
Reading Text Input: Processing Lines
Then extract the country name and population:
String countryName = line.substring(0, i);
String population = line.substring(i);
Use the trim method to remove spaces at the end of the country name:
countryName = countryName.trim();
To convert the population string to a number, first trim it, then call the Integer.parseInt method:
int populationValue = Integer.parseInt(population.trim());
Reading Text Input: Processing Lines
Occasionally easier to construct a new Scanner object to read the
characters from a string:
Scanner lineScanner = new Scanner(line);
Then you can use lineScanner like any other Scanner object, reading words and numbers:
String countryName = lineScanner.next();
while (!lineScanner.hasNextInt())
{
countryName = countryName + " " + lineScanner.next();
}
int populationValue = lineScanner.nextInt();
Reading Text Input: Reading Numbers
nextInt and nextDouble methods consume white space and the next number:
double value = in.nextDouble();
If there is no number in the input, then a InputMismatchException occurs; e.g.
To avoid exceptions, use the hasNextDouble and hasNextInt methods to screen the input:
if (in.hasNextDouble())
{
double value = in.nextDouble();
. . .
}
Reading Text Input: Reading Numbers
nextInt and nextDouble methods do not consume the white space
that follows a number
Example: file contains student IDs and names in
this format:
1729
Harry Morgan
1730
Diana Lin
. . .
Read the file with these instructions:
while (in.hasNextInt())
{
int studentID = in.nextInt();
String name = in.nextLine();
Process the student ID and name
}
Reading Text Input: Reading Numbers
Initially, the input contains
After the first call to nextInt, the input contains
The call to nextLine reads an empty string! The remedy is to add a call to nextLine after reading the ID:
int studentID = in.nextInt();
in.nextLine(); // Consume the newline
String name = in.nextLine();
Reading Text Input: Reading Characters
To read one character at a time, set the delimiter pattern to the empty string:
Scanner in = new Scanner(. . .);
in.useDelimiter("");
Now each call to next returns a string consisting of a single character
To process the characters:
while (in.hasNext())
{
char ch = in.next().charAt(0);
Process ch
}
Self Check 11.3
Suppose the input contains the characters 6,995.0. What is the value of number and input after these statements?
int number = in.nextInt();
String input = in.next();
Answer:number is 6, input is ",995.0".
Self Check 11.4
Suppose the input contains the characters 6,995.00 12. What is the value of price and quantity after these statements?
double price = in.nextDouble();
int quantity = in.nextInt();
Answer:price is set to 6 because the comma is not considered a part of a floating-point number in Java. Then the call to nextInt causes an exception, and quantity is not set.
Self Check 11.5
Your input file contains a sequence of numbers, but sometimes a value is not available and marked as N/A. How can you read the numbers and skip over the
markers?
Answer:
Read them as strings, and convert those strings to numbers that are not equal to N/A:
String input = in.next();
if (!input.equals("N/A"))
{
double value = Double.parseDouble(input);
Process value
}
Throwing Exceptions
Throw an exception object to signal an exceptional condition
Programmer cannot prevent users from entering incorrect input
This choice makes the class easy to use for beginning programmers
Deal with checked exceptions principally when programming with files and streams
For example, use a Scanner to read a file:
String filename = . . .;
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
But, FileReader constructor can throw a FileNotFoundException
Checked and Unchecked Exceptions
Two choices:
Handle the exception
Tell compiler that you want method to be terminated when the exception occurs
Use throws specifier so method can throw a checked exception
public void read(String filename) throws FileNotFoundException
{
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
. . .
}
For multiple exceptions:
public void read(String filename)
throws IOException, ClassNotFoundException
Keep in mind inheritance hierarchy:
If method can throw an IOException and FileNotFoundException,
only use IOException
Better to declare exception than to handle it incompetently
Syntax 11.2throws Clause
Self Check 11.8
Suppose a method calls the Scanner constructor, which can throw a FileNotFoundException, and the nextInt method of the Scanner class, which can cause a
NoSuchElementException or InputMismatchException. Which exceptions should be
included in the throws clause?
Answer:
You must include the FileNotFoundException and you may include the NoSuchElementException if you consider it important for documentation purposes. InputMismatchException is a subclass of NoSuchElementException. It is your choice whether to include it.
Self Check 11.9
Why is a NullPointerException not a checked exception?
Answer:
Because programmers should simply check for null pointers instead of
trying to handle a NullPointerException.
Catching Exceptions
Install an exception handler with try/catch statement
try block contains statements that may cause an exception
catch clause contains handler for an exception type:
try
{
String filename = . . .;
FileReader reader = new FileReader(filename);
Scanner in = new Scanner(reader);
String input = in.next();
int value = Integer.parseInt(input);
. . .
}
catch (IOException exception)
{
exception.printStackTrace();
}
catch (NumberFormatException exception)
{
System.out.println("Input was not a number");
}
Catching Exceptions
Statements in try block are executed
If no exceptions occur, catch clauses are skipped
If exception of matching type occurs, execution jumps to catch clause
If exception of another type occurs, it is thrown until it is caught by another try
block
catch (IOException exception) block
exception contains reference to the exception object that was thrown
catch clause can analyze object to find out more details
exception.printStackTrace(): printout of chain of method calls that
lead to exception
Syntax 11.3 Catching Exceptions
Self Check 11.10
Suppose the file with the given file name exists and has no contents. Trace the
flow of execution in the try block in this section.
Answer:
The FileReader constructor succeeds, and in is constructed. Then the
call in.next() throws a NoSuchElementException, and the try
block is aborted. None of the catch clauses match, so none are executed.
If none of the enclosing method calls catch the exception, the program
terminates.
Self Check 11.11
Is there a difference between catching checked and unchecked exceptions?
Answer:
No – you catch both exception types in the same way, as you can see from the
above code example. Recall that IOException is a checked
exception and NumberFormatException is an unchecked exception.
The finally Clause
Exception terminates current method
Danger: Can skip over essential code
Example:
reader = new FileReader(filename);
Scanner in = new Scanner(reader);
readData(in);
reader.close(); // May never get here
Must execute reader.close() even if exception happens
Use finally clause for code that must be executed no matter what
The finally Clause
FileReader reader = new FileReader(filename);
try
{
Scanner in = new Scanner(reader);
readData(in);
}
finally
{
reader.close(); // if an exception occurs, finally clause is also
// executed before exception is passed to its handler
}
The finally Clause
Executed when try block is exited in any of three ways:
After last statement of try block
After last statement of catch clause, if this try block caught
an exception
When an exception was thrown in try block and not caught
Recommendation: don't mix catch and finally clauses in same try
block
Syntax 11.4finally Clause
Self Check 11.12
Why was the out variable declared outside the try block?
Answer:
If it had been declared inside the try block, its scope would only have
extended to the end of the try block, and the finally clause could not have closed it.
Self Check 11.13
Suppose the file with the given name does not exist. Trace the flow of execution
of the code segment in this section.
Answer:
The PrintWriter constructor throws an exception. The assignment to out and the try block are skipped. The finally clause is not executed. This is the correct behavior because out has not been initialized.
Designing Your Own Exception Types
You can design your own exception types — subclasses of Exception or RuntimeException
if (amount > balance)
{
throw new InsufficientFundsException(
"withdrawal of " + amount + " exceeds balance of " + balance);
}
Make it an unchecked exception — programmer could have avoided it by calling getBalance
first
Extend RuntimeException or one of its subclasses
Supply two constructors
Default constructor
A constructor that accepts a message string describing reason for exception
Designing Your Own Exception Types
public class InsufficientFundsException
extends RuntimeException
{
public InsufficientFundsException() {}
public InsufficientFundsException(String message)
{
super(message);
}
}
Self Check 11.14
What is the purpose of the call super(message) in the second InsufficientFundsException
constructor?
Answer:
To pass the exception message string to the RuntimeException superclass.
Self Check 11.15
Suppose you read bank account data from a file. Contrary to your expectation,
the next input value is not of type double. You decide to implement a BadDataException.
Which exception class should you extend?
Answer:
Because file corruption is beyond the control of the programmer, this should be a checked exception, so it would be wrong to extend RuntimeException or IllegalArgumentException. Because the error is related to input, IOException would be a good choice.
Case Study: A Complete Example
Program
Asks user for name of file
File expected to contain data values
First line of file contains total number of values
Remaining lines contain the data
Typical input file:
3
1.45
-2.1
0.05
Case Study: A Complete Example
What can go wrong?
File might not exist
File might have data in wrong format
Who can detect the faults?
FileReader constructor will throw an exception when file does not exist
Methods that process input need to throw exception if they find error in data
format
What exceptions can be thrown?
FileNotFoundException can be thrown by FileReader constructor
IOException can be thrown by close method of FileReader
BadDataException, a custom checked exception class
Who can remedy the faults that the exceptions report?
Only the main method of DataSetTester program interacts with
user
Catches exceptions
Prints appropriate error messages
Gives user another chance to enter a correct file
ch11/data/DataAnalyzer.java
The readFile Method of the DataSetReader Class
Constructs Scanner object
Calls readData method
Completely unconcerned with any exceptions
If there is a problem with input file, it simply passes the exception to caller:
public double[] readFile(String filename)
throws IOException, BadDataException
// FileNotFoundException is an IOException
{
FileReader reader = new FileReader(filename);
try
{
Scanner in = new Scanner(reader);
readData(in);
}
finally
{
reader.close();
}
return data;
}
The readFile Method of the DataSetReader Class
Reads the number of values
Constructs an array
Calls readValue for each data value:
private void readData(Scanner in) throws BadDataException
{
if (!in.hasNextInt())
throw new BadDataException("Length expected");
int numberOfValues = in.nextInt();
data = new double[numberOfValues];
for (int i = 0; i < numberOfValues; i++)
readValue(in, i);
if (in.hasNext())
throw new BadDataException("End of file expected");
}
Checks for two potential errors
File might not start with an integer
File might have additional data after reading all values
Makes no attempt to catch any exceptions
The readValue method of the DataSetReader class
private void readValue(Scanner in, int i) throws BadDataException
{
if (!in.hasNextDouble())
throw new BadDataException("Data value expected");
data[i] = in.nextDouble();
}
readValue doesn't find expected value and throws BadDataException
readValue has no handler for exception and terminates
readData has no handler for exception and terminates
readFile has no handler for exception and terminates after executing finally
clause
DataSetTester.main has handler for BadDataException; handler
prints a message, and user is given another chance to enter file name
ch11/data/DataSetReader.java
ch11/data/BadDataException.java
Self Check 11.16
Why doesn't the DataSetReader.readFile method catch any exceptions?
Answer:
It would not be able to do much with them. The DataSetReader class is a
reusable class that may be used for systems with different languages and
different user interfaces. Thus, it cannot engage in a dialog with the program
user.
Self Check 11.17
Suppose the user specifies a file that exists and is empty. Trace the flow of
execution.
Answer:DataSetAnalyzer.main calls DataSetReader.readFile, which calls readData.
The call in.hasNextInt() returns false, and readData
throws a BadDataException. The readFile method doesn't catch
it, so it propagates back to main, where it is caught.