test02
- 11 Input/Output and Exception Handling
- 11.1 Reading and Writing Text Files
- 11.1.1 Reading from a file
- 11.1.2 Writing to a file
- Example 11.1.1
- Self-Check Qustion 11.1.1
- Common Error 11.1.1 - Backslashes in File Names
- Common Error 11.1.2 - Constructing a Scanner with a String
- Special Topic 11.1.1 - File Dialog Boxes
- Special Topic 11.1.2 - Reading Web Pages
- Special Topic 11.1.3 - Command Line Arguments
- Special Topic 11.1.4 - Batch Files and Shell Scripts
- 11.2 Reading Text Input
- 11.3 Throwing Exceptions
- 11.4 Checked and Unchecked Exceptions
- 11.5 Catching Exceptions
- 11.6 The finally Clause
- 11.7 Designing Your Own Exception Types
- 11.8 Case Study: A Complete Example
- Summary of Chapter 11
- Project 11.1
- 11.1 Reading and Writing Text Files
11 Input/Output and Exception Handling
11.1 Reading and Writing Text Files
11.1.1 Reading from a file
The simplest mechanism for reading text is to use the Scanner
class. To read input from a disk file, Scanner
relies on File
, which describes disk files and directories.
First construct a File object with the name of the input file, then use the File to construct a Scanner object:
File inFile = new File("input.txt");
Scanner in = new Scanner(inFile);
You then can use the Scanner methods (such as next
, nextLine
, nextInt
, and nextDouble
) to read data from the input file.
Close the Scanner
as soon as you are done with it:
in.close();
11.1.2 Writing to a file
To write output to a file, us the PrintWriter
class:
PrintWriter out = new PrintWriter("output.txt");
If the output file already exists, it is emptied before the new data are written into it. If the file doesn’t exist, an empty file is created.
You can also construct a PrintWriter
object passing in a File
object. This is useful if you use a file chooser (see Special Topic 11.1).
The PrintWriter class is an enhancement of the PrintStream
class which System.out
is an object of. So the familiar print
, println
, and printf
methods can be used with any PrintWriter object:
out.print(29.95);
out.println(new Rectangle(5, 10, 15, 25));
out.printf("%10.2f", price);
You must close the PrintWriter
object:
out.close();
If your program exits without closing the PrintWriter
, the disk file may not contain all of the output.
Example 11.1.1
The following program reads all lines of an input file and sends them to the output file, preceded by line numbers. If the input file is
Mary had a little lamb
Whose fleece was white as snow.
and everywhere that Mary went,
The lamb was sure to go!
then the 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!
The line numbers are enclosed in /* */ delimiters so that the program can be used for numbering Java source files.
When the input or output file doesn’t exist, a FileNotFoundException
can occur. The compiler insists that we tell it what the program should do when that happens. In our sample program, we take the easy way out and acknowledge that the main
method should simply be terminated if the exception occurs.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;
/**
This program applies line numbers to a file.
*/
public class LineNumberer {
public static void main(String[] args) throws FileNotFoundException {
// Prompt for the input and output file names
Scanner console = new Scanner(System.in);
System.out.print("Input file: ");
String inputFileName = console.next();
System.out.print("Output file: ");
String outputFileName = console.next();
// Construct the Scanner and PrintWriter objects for reading and writing
File inputFile = new File(inputFileName);
Scanner in = new Scanner(inputFile);
PrintWriter out = new PrintWriter(outputFileName);
int lineNumber = 1;
// Read the input and write the output
while (in.hasNextLine()) {
String line = in.nextLine();
out.println("/* " + lineNumber + " */ " + line);
lineNumber++;
}
in.close();
out.close();
}
}
Self-Check Qustion 11.1.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.
Common Error 11.1.1 - Backslashes in File Names
When you specify a file name as a string literal, and the name contains backslash characters (as in a Windows file name), you must supply each backslash twice:
inFile = new File("c:\\homework\\input.dat");
Recall that a single backslash inside quoted strings is an escape character that is combined with another character to form a special meaning, such as \n for a newline character. The \\
combination denotes a single backslash.
When a user supplies a file name to a program, however, the user should not type the backslash twice.
Common Error 11.1.2 - Constructing a Scanner with a String
Unlike with PrintWriter
, the statement
Scanner in = new Scanner("input.txt"); // ERROR?
does not open a file. Instead, it simply reads through the string: in.nextLine()
returns the string "input.txt". This feature can be useful—see Section 11.2.3 for an example.
Special Topic 11.1.1 - File Dialog Boxes
Special Topic 11.1 shows you how you can present a file chooser dialog box to users of your programs.
Special Topic 11.1.2 - Reading Web Pages
You can read the contents of a web page with this sequence of commands:
String address = "http://java.sun.com/index.html";
URL locator = new URL(address);
Scanner in = new Scanner(locator.openStream());
Now simply read the contents of the web page with the Scanner in the usual way. The URL constructor and the openStream method can throw an IOException. You need to tag the main method with throws IOException.
Special Topic 11.1.3 - Command Line Arguments
Graphical user interfaces are easier and more natural to use but hard to automate. So an alternative way is to run a Java program in a terminal or shell window, called “invoking the program from the command line”. You can also type in additional information, called command line arguments, after the name of the program and it will be placed into the args parameter of the main
method.
For example, to specify the input and output file names for the LineNumberer
program on the command line:
java LineNumberer input.txt numbered.txt
The args
parameter of the LineNumberer.main
method has the following contents:
• args[0]is "input.txt"
• args[1]is "numbered.txt"
The mainmethod can then process these parameters, for example:
if (args.length >= 1)
inputFileName = args[0];
It is customary to interpret strings starting with a hyphen (–) as program options. For example, we may want to enhance the LineNumberer
program so that a -c
option places line numbers inside comment delimiters:
java LineNumberer -c HelloWorld.java HelloWorld.txt
If the -c
option is missing, the delimiters should not be included. Here is how the main method can analyze the command line arguments:
for (String arg : args) {
if (arg.startsWith("-")) { // It’s an option
if (arg.equals("-c")) useCommentDelimiters = true;
}
else if (inputFileName == null) inputFileName = arg;
else if (outputFileName == null) outputFileName = arg;
}
Special Topic 11.1.4 - Batch Files and Shell Scripts
It's used to perform the same tasks repeatedly on the command line.
Under Windows, we use batch files. Suppose you need to test a program by running three testers, you can put the commands in a text file and call it test.bat
:
File test.bat
java BankTester1
java BankTester2
java BankTester3 < input1.txt
Then you just type
test.bat
and the three commands in the batch file execute automatically.
On Linux, Mac OS, and UNIX, shell scripts are used for the same purpose. In this simple example, you can execute the commands by typing
sh test.bat
11.2 Reading Text Input
11.2.1 Reading Words
The next
method reads a word at a time, as a 'String' object, rather than lines. Usually used with a loop and `hasNext' method. For example:
while (in.hasNext()) {
String input = in.next();
System.out.println(input);
}
This loop would print a word on every line.:
In Java, a word is a continuous sequence of non-whitespace characters. If you want to discard anything that isn’t a letter (not only whitespaces), you can call the useDelimiter
method on your Scanner
object before reading. For exmaple, to set the character pattern that separates words to “any sequence of characters other than letters”:
Scanner in = new Scanner(. . .);
in.useDelimiter("[^A-Za-z]+");
With this setting, punctuation and numbers are stripped off from the words returned by the next
method.
11.2.2 Processing Lines
The nextLine
method consumes (remove from the stream) the next input line (including the newline character) and returns the line without the newline character. It is useful when each line of a file is a data record:
String line = in.nextLine();
Here is a typical example of processing lines in a file. A file with population data contains lines such as the following:
...
China 1330044605
India 1147995898
United States 303824646
...
There are two ways to parse this file using Java. The first is by looking at individual characters, and the other is to use methods of the Scanner
class.
Character by Character
Because some country names have more than one word, it would be tedious to read this file using the next
method. Instead, 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.
Locate the first digit:
int i = 0;
while (!Character.isDigit(line.charAt(i))) { i++; }
Then extract the country name and population:
String countryName = line.substring(0, i);
String population = line.substring(i);
Then use the trim
method to remove all white space at the beginning and end:
countryName = countryName.trim();
At last, use the Integer.parseInt
method to convert the population:
int populationValue = Integer.parseInt(population);
Integer.parseInt
's parameter value must be a string containing the digits of an integer or a NumberFormatException
occurs. The parameter value may not contain any additional characters. Not even spaces are allowed!
int populationValue = Integer.parseInt(population.trim());
Using Methods of Scanner
Construct a new Scanner object to read the characters from a string:
Scanner lineScanner = new Scanner(line);
Then you can use lineScanner to read words and numbers:
String countryName = lineScanner.next();
while (!lineScanner.hasNextInt()) {
countryName = countryName + " " + lineScanner.next();
}
int populationValue = lineScanner.nextInt();
11.2.3 Reading Numbers
The nextInt
and nextDouble
methods consume leading whitespaces and the next number.
Suppose you call
double value = in.nextDouble();
The nextDouble
method recognizes floating-point numbers such as 3.14159, -21, or 1E12 (a billion in scientific notation). However, if there is no number in the input, then a NoSuchElementException
occurs. So use it with the hasNextDouble
method to check ahead:
if (in.hasNextDouble()) {
double value = in.nextDouble();
...
}
Similarly, you should call the hasNextInt
method before calling nextInt
.
Note that the nextInt and nextDouble methods do not consume the white space that follows a number. This can be a problem if you alternate between calling nextInt
/nextDouble
and nextLine
. Suppose a file contains student IDs and names in this format:
1729
Harry Morgan
1730
Diana Lin
...
Now suppose you read the file with these instructions:
while (in.hasNextInt()) {
int studentID = in.nextInt();
String name = in.nextLine();
Process the student ID and name
}
Initially, the input contains
1729\nHarry
After the first call to nextInt, the input contains
\nHarry
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();
11.2.4 Reading Characters
To read one character at a time, calling the Scanner.useDelimiter
method with an empty string as the delimiter pattern:
Scanner in = new Scanner(. . .);
in.useDelimiter("");
Now each call to next
returns a string consisting of a single character:
while (in.hasNext()) {
char ch = in.next().charAt(0);
Process ch
}
Self-Check Question 11.2.1
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 Question 11.2.2
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.
Weired Question 11.2.3
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
Special Topic 11.2.1 - Regular Expressions and grep
Regular expressions describe character patterns.
For numbers, the pattern is [0-9]+
, where the set [0-9]
denotes any digit between 0 and 9, and the +
means “one or more”.
A commonly used program that uses regular expressions is grep (which stands for “global regular expression print”). You can run grep from a command line or from inside some compilation environments. Grep is part of the UNIX operating system, and versions are available for Windows. It needs a regular expression and one or more files to search, and then displays a set of lines that match the regular expression.
The command
grep [0-9]+ Homework.java
lists all lines in the file Homework.java
that contain sequences of digits.
In the more complex command
grep [^A-Za-z][0-9]+ Homework.java
the set [^A-Za-z] denotes any characters that are not in the ranges A
to Z
and a
to z
. This works much better, and it shows only lines that contain actual numbers.
The useDelimiter
method of the Scanner
class accepts a regular expression to describe delimiters—the blocks of text that separate words.
Example 11.2.1
**ch11/population/CountryValue.java **
/**
Describes a value that is associated with a country.
*/
public class CountryValue {
private String country;
private double value;
/**
Constructs a CountryValue from an input line.
@param line a line containing a country name, followed by a value
*/
public CountryValue(String line) {
// Locate the start of the first digit
int i = 0;
while (!Character.isDigit(line.charAt(i))) { i++; }
// Locate the end of the preceding word
int j = i - 1;
while (Character.isWhitespace(line.charAt(j))) { j--; }
// Extract the country name
country = line.substring(0, j + 1);
value = Double.parseDouble(line.substring(i).trim()); // Extract the value
}
/**
Gets the country name.
@return the country name
*/
public String getCountry() { return country; }
/**
Gets the associated value.
@return the value associated with the country
*/
public double getValue() { return value; }
}
**ch11/population/PopulationDensity.java **
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;
public class PopulationDensity {
public static void main(String[] args) throws FileNotFoundException {
// Open input files
Scanner in1 = new Scanner(new File("worldpop.txt"));
Scanner in2 = new Scanner(new File("worldarea.txt"));
// Open output file
PrintWriter out = new PrintWriter("world_pop_density.txt");
// Read lines from each file
while (in1.hasNextLine() && in2.hasNextLine()) {
CountryValue population = new CountryValue(in1.nextLine());
CountryValue area = new CountryValue(in2.nextLine());
// Compute and print the population density
double density = 0;
// Protect against division by zero
if (area.getValue() != 0) {
density = population.getValue() / area.getValue();
}
out.printf("%-40s%15.2f\n", population.getCountry(), density);
}
in1.close();
in2.close();
out.close();
}
}
Example 11.2.2
In this Worked Example, you will use data from the Social Security Administration to analyze the most popular baby names.
11.3 Throwing Exceptions
Two main aspects to exception handling: reporting and recovery.
To signal an exceptional condition, use the throw
statement to throw an exception object, and the current method terminates immediately.
throw [exceptionObject];
The Java library provides many classes to signal all sorts of exceptional conditions, as shown below.
For exmaple:
public class BankAccount {
public void withdraw(double amount) {
if (amount > balance) {
throw new IllegalArgumentException("Amount exceeds balance");
}
balance = balance - amount;
}
...
}
11.4 Checked and Unchecked Exceptions
There are two kinds of Java exceptions: checked and unchecked exceptions.
If a method that throws a checked exception, compiler will check it to ensure that you tell the compiler what you are going to do about it.
On the other hand, for unchecked exceptions, the compiler does not do the checking because you are not required to keep track of them. Like NullPointerException
.
Unchecked exceptions extend the class RuntimeException
or Error
. And all other subclasses of the class Exception
are checked.
A checked exception is due to external circumstances and the programmer cannot prevent. The unchecked exceptions, on the other hand, are your fault.
Actually, those categories aren’t perfect. For example, the Scanner.nextInt
method throws an unchecked InputMismatchException
if the input does not contain a valid integer. A checked exception would have been more appropriate because the programmer cannot prevent users from entering incorrect input. (The designers of the Scanner class made this choice to make it easy to use for beginning programmers, such that they can use it without providing handling mechanism).
The majority of checked exceptions occur when you deal with input and output. Therefore, you will need to deal with checked exceptions principally when programming with files and streams.
The Scanner
constructor can throw a FileNotFoundException
, a checked exception, so you need to report (and let the method terminates) or handle it. You have two choices. To declare that a method should be terminated when a checked exception occurs within it, tag the method with a throws clause.
For example:
public void read(String filename) throws FileNotFoundException {
File inFile = new File(filename);
Scanner in = new Scanner(inFile);
...
}
Sseparate all the checked exception class names by commas after a method which can throw more than one type of checked exceptions (mind the inheritance hierarchy and throw the higher one):
public void read(String filename)
throws FileNotFoundException, NoSuchElementException
You may also list unchecked exceptions that this method may throw.
It is usually best not to catch an exception, especially a lower-level one, if you don’t know how to remedy the situation.
11.5 Catching Exceptions
Every exception should be handled somewhere in your program. If an exception has no handler, an error message is printed, and your program terminates.
To handle an exception, place the statements that can cause the exception inside a tryblock, and the handler inside a catchclause.
Here is an example:
try {
String filename = . . .;
File inFile = new File(filename);
Scanner in = new Scanner(inFile);
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");
}
The Scanner
constructor can throw a FileNotFoundException
, Scanner.next
can throw a NoSuchElementException
, and Integer.parseInt
can throw a NumberFormatException
.
If any of these exceptions is actually thrown, then the rest of the instructions in the try block are skipped. Here is what happens for the various exception types:
- If a
FileNotFoundException
is thrown, then the catch clause for theIOException
is executed. (Recall thatFileNotFoundException
is a subclass ofIOException
.) - If a
NumberFormatException
occurs, then the second catch clause is executed. - A
NoSuchElementException
is not caught by any of the catch clauses. The exception remains thrown until it is caught by another try block or the main method terminates.
You can get a printout of the chain of method calls that lead to the exception, by calling
exception.printStackTrace();
It is important to remember that you should place catch clauses only in methods in which you can competently handle the particular exception type.
Special Topic 11.5.1 - Throw Early, Catch Late
Throw an exception as soon as a problem is detected. Catch it only when the problem can be handled.
Special Topic 11.5.2 - Do Not Squelch Exceptions
Don't fool the compile with a quick yet false handler like this:
try {
File inFile = new File(filename);
Scanner in = new Scanner(inFile);
// Compiler complained about FileNotFoundException
...
} catch (Exception e) {} // So there!
Exceptions were designed to transmit problem reports to a competent handler. Installing an incompetent handler simply hides an error condition that could be serious.
11.6 The finally Clause
Once a try
block is entered, the statements in a finally
clause are guaranteed to be executed whenever the try
block is exited in any of three ways:
- After completing the last statement of the try block
- After completing the last statement of a catch clause, if this try block caught an exception
- When an exception was thrown in the try block and not caught
Here is a typical situation. It is important to close a PrintWriter
to ensure that all output is written to the file:
PrintWriter out = new PrintWriter(filename);
try {
writeData(out);
} finally {
out.close();
}
Note that the out
stream is created outside the try
clause, or else the finally
clause may not be able to access it.
Special Topic 11.6.1 - Do Not Use catch
and finally
in the Same try
Statement
Use a try/finally statement to close resources and a separate try/catch statement to handle errors. For example:
try {
PrintWriter out = new PrintWriter(filename);
try {
// Write output to out
...
} finally {
out.close();
}
} catch (IOException exception) {
// Handle exception
...
}
Special Topic 11.6.2 - Automatic Resource Management in Java 7
In Java 7, you can use a new form of the try block that automatically closes an object that implements the Closeable interface, such as a PrintWriter
or Scanner
. Here is the syntax:
try (PrintWriter out = new PrintWriter(filename)) {
// Write output to out
}
The close
method is automatically invoked on the out object when the try
block ends, whether or not an exception has occurred. A finally
statement is not required.
11.7 Designing Your Own Exception Types
You can design your own exception class to describe your own particular exceptional condition. Consider a bank account. Let’s report an InsufficientFundsException when an attempt is made to withdraw an amount from a bank account that exceeds the current balance.
if (amount > balance) {
throw new InsufficientFundsException("withdrawal of " + amount + " exceeds balance of " + balance);
}
To describe an error condition, provide a subclass of an existing exception class.
When we do this, we first need to determine it's a checked exception or an unchecked one.
It is customary to provide two constructors for an exception class: a constructor with no parameters and a constructor that accepts a message string describing the reason for the exception. When an exception constructed via the latter one is caught, its message string can be retrieved using the getMessage
method of the Throwable
class.
Here is the declaration of the exception class used above.
public class InsufficientFundsException extends IllegalArgumentException {
// The 'empty' constructor
public InsufficientFundsException() {}
// The one with a message
public InsufficientFundsException(String message) {
super(message);
}
}
Special Topic 11.7.1 - Do Throw Specific Exceptions
When throwing an exception, you should choose an exception class that describes the situation as closely as possible.
If the standard library does not have an exception class that describes your particular error situation, simply provide a new exception class.
11.8 Case Study: A Complete Example
What's the task?
This section walks through a complete example of a program with exception handling. The program asks a user for the name of a file. The file is expected to contain data values. The first line of the file contains the total number of values, and the remaining lines contain the data. A typical input file looks like this:
3
1.45
-2.1
0.05
What can go wrong?
There are two principal risks.
- The file might not exist.
- The file might have data in the wrong format.
Who can detect these faults?
-
The
Scanner
constructor will throw an exception when the file does not exist. -
The methods that process the input values need to throw an exception when they find an error in the data format.
What exceptions can be thrown?
-
The
Scanner
constructor throws aFileNotFoundException
when the file does not exist, which is appropriate in our situation. -
When the file data is in the wrong format, we will throw a
BadDataException
, a custom checked exception class. We use a checked exception because corruption of a data file is beyond the control of the programmer.
Who can remedy the faults that the exceptions report?
Only the main
method of the DataAnalyzer
program interacts with the user. It catches the exceptions, prints appropriate error messages, and gives the user another chance to enter a correct file.
ch11/data/DataAnalyzer.java
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;
/**
This program reads a file containing numbers and analyzes its contents.
If the file doesn’t exist or contains strings that are not numbers, an
error message is displayed.
*/
public class DataAnalyzer {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
DataSetReader reader = new DataSetReader();
boolean done = false;
// The loop always gives another chance for the use to input
// a right file name after an 'handlable' exception
while (!done) {
try {
System.out.println("Please enter the file name: ");
String filename = in.next();
double[] data = reader.readFile(filename);
double sum = 0;
for (double d : data) sum = sum + d;
System.out.println("The sum is " + sum);
done = true;
} catch (FileNotFoundException exception) {
System.out.println("File not found.");
} catch (BadDataException exception) {
System.out.println("Bad data: " + exception.getMessage());
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
}
**ch11/data/DataSetReader.java **
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
/**
Reads a data set from a file. The file must have the format
numberOfValues (int)
value1 (double)
value2 (double)
...
*/
public class DataSetReader {
private double[] data;
/**
Reads a data set.
@param filename the name of the file holding the data
@return the data in the file
*/
public double[] readFile(String filename) throws IOException {
File inFile = new File(filename);
Scanner in = new Scanner(inFile);
try {
readData(in);
return data;
} finally {
in.close();
}
}
/**
Reads all data.
@param in the scanner that scans the data
*/
private void readData(Scanner in) throws BadDataException {
if (!in.hasNextInt())
throw new BadDataException("Length expected");
int numberOfValues = in.nextInt();
if (numberOfValues <= 0)
throw new BadDataException("Positive length expected");
data = new double[numberOfValues];
for (int i = 0; i < numberOfValues; i++)
readValue(in, i);
if (in.hasNext())
throw new BadDataException("End of file expected");
}
/**
Reads one data value.
@param in the scanner that scans the data
@param i the position of the value to read
*/
private void readValue(Scanner in, int i) throws BadDataException {
if (!in.hasNextDouble())
throw new BadDataException("Data value expected");
data[i] = in.nextDouble();
}
}
The readFile
method throws an IOException
, the common superclass o FileNotFoundException
(thrown by the Scanner constructor) and BadDataException
(thrown by the readData
method).
Even if an expection obeject has been thrown as a super-class object, it can still be caught by a catch
claused specified to its original class.
ch11/data/BadDataException.java
import java.io.IOException;
/**
This class reports bad input data.
*/
public class BadDataException extends IOException {
public BadDataException() {}
public BadDataException(String message) {
super(message);
}
}
This example shows the separation between error detection (in the DataSetReader.readValue
method) and error handling (in the DataAnalyzer.main
method). In between the two are the readData
and readFile
methods, which just pass exceptions along.
Summary of Chapter 11
Read and write text that is stored in files
- When reading text files, use the
Scanner
class. - When writing text files, use the
PrintWriter
class. - You must close a print stream when you are done writing output.
4 mechanisms for obtaining file names
-
Hard-coding the file names (such as "worldpop.txt").
-
Asking the user:
Scanner in = new Scanner(System.in); System.out.print("Enter filename: "); String inFile = in.nextLine();
-
Using command line arguments for the file names.
-
Using a file dialog box.
Choose an appropriate mechanism for processing input
- When the data are distributed over several lines, then it makes more sense to read words. The
next
method reads a word at a time. CallScanner.useDelimiter
to specify a pattern for word separators which will be discarded. - Read lines if the input data is grouped by lines. The
nextLine
method reads a line of input, consumes and discards the newline character at the end of the line. - The
nextInt
andnextDouble
methods consume leading whitespaces and the next number but not whitespaces after and only return the number. - To read one character at a time, set the delimiter pattern to the empty string.
Understand when and how to throw an exception
- To signal an exceptional condition, use the throw statement to throw an exception object.
- When you throw an exception, the current method terminates immediately.
**Choose between checked and unchecked exceptions. **
- There are two kinds of exceptions: checked and unchecked. Unchecked exceptions extend the class RuntimeException or Error.
- Checked exceptions are due to external circumstances that the programmer cannot prevent. The compiler checks that your program handles these exceptions.
- Add a
throws
clause to a method that can throw a checked exception.
Use exception handlers to decouple error detection and error reporting
- In a method that is ready to handle a particular exception type, place the statements that can cause the exception inside a
try
block, and the handler inside acatch
clause. - Throw an exception as soon as a problem is detected. Pass it along until it can be handled and then catch it.
- Use the finally clause to ensure that resources are released when an exception is thrown.
- Once a try block is entered, the statements in a finally clause are guaranteed to be executed, whether or not an exception is thrown.
Design exception types to describe error conditions
- To describe an error condition, provide a subclass of an existing exception class.
Project 11.1
You can read the contents of a web page with this sequence of commands.
String address = "http://java.sun.com/index.html";
URL u = new URL(address);
Scanner in = new Scanner(u.openStream());
...
Some of these methods may throw exceptions—check out the API documentation.
Design a class LinkFinder
that finds all hyperlinks of the form <a href="link">link text</a>
.
Throw an exception if you find a malformed hyperlink. Extra credit if your program can follow the links that it finds and find links in those web pages as well.
(This is the method that search engines such as Google use to find web sites.)