- COMP.CS.140
- 4. Programming in the Large
- 4.3 Exception handling in Java
Exception handling in Java¶
We briefly review Java’s try
-catch
statement for exception handling.
It was mentioned earlier that e.g. many input operations require us to somehow acknowledge possible exceptions. Consider the following simple program:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class NameLength {
public static void main(String[] args) {
var input = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter your name: ");
String name = input.readLine();
System.out.format("Your name \"%s\" has %d characters%n",
name, name.length());
}
}
Attempt to compile the code would result in a compiler error similar to:
NameLength.java:8: error: unreported exception IOException; must be caught or declared to be thrown
String name = input.readLine();
Earlier we simply ignored exceptions: instead of handling them, we added to the function header
an exception specification that lists the exception types that may propagate out from the function
(because we do not handle them). A second option would be to handle (or “catch”) the exceptions
ourselves. This can be done in Java by using a very similar so-called try
-catch
statement
as e.g. in C++ or Python. Java’s try
-catch
statement has the following structure:
// Enclose the code that may cause an exception into a try block.
try {
// A code block that may cause exceptions either directly in the code block itself or
// indirectly by propagating exceptions out from some function called in this block.
}
// A try block is followed by catch blocks that can handle ("catch") exceptions that occur
// in the preceding try block. Here we give as an example two catch blocks that handle two
// types of exceptions: ExceptionTypeA and ExceptionTypeB.
catch(ExceptionTypeA parameter) {
// A code block into which the program execution will directly jump if an exception of
// type ExceptionTypeA occurs in the preceding try block.
}
catch(ExceptionTypeB parameter) {
// A code block into which the program execution will directly jump if an exception of
// type ExceptionTypeB occurs in the preceding try block.
}
// Catch blocks can be followed by a single finally block that will be executed always,
// ie. regardless of whether the try block caused an exception and whether any corresponding
// catch block was executed. If no exception occurs, the finally lock will be executed
// immediately after the try block. If an exception does occur, the finally block will be
// executed after a possible matching catch block.
finally {
// A code block that will always be executed regardless of exceptions.
}
The catch
blocks receive an object of the handled exception type as a parameter. These
exception parameters may convey some information about what kind of an exception occurred.
If the same catch
block is suitable for handling several exception types, Java allows a
catch
block parameter to list several exception types separated by vertical bar characters
‘|’. Note that a catch
block will have only a single parameter also in this case. An example:
try {
// A code block that might cause an exception.
}
catch(ExceptionTypeA | ExceptionTypeB parameter) {
// A code block into which the program execution jumps if the preceding
// try block causes an exception of type ExceptionTypeA or ExceptionTypeB.
}
The code shown in the beginning of this section will compile if we add to it a try
-catch
statement that handles exceptions of type IOException
. The example below simply prints out
information about the caught exception:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class NameLength {
public static void main(String[] args) {
var input = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter your name: ");
try { // An IOException exception may occur within this code block.
String name = input.readLine();
System.out.format("Your name \"%s\" has %d characters%n",
name, name.length());
}
catch(IOException e) { // A handler for IOException exception.
System.out.println("An exception occurred: " + e);
}
}
}
We will dicuss some further technical aspects of try
-catch
statements later.
One thing to note is that exceptions are not used only for indicating serious errors. Exceptions
provide a general program flow control mechanism that allows code execution to jump from one point
(where an exception occurs, or is “thrown”) directly to another point (into a catch
block that
handles the exception). Although many exceptions do arise from serious errors (e.g. the program
executes some illegal operation, runs out of memory, etcs.), exceptions are also used in fairly
“routine” manner to e.g. convey information about the result of a function call. For example the
string parsing functions of the number wrapper classes (Integer
, Double
etc.) throw an
exception of type NumberFormatException
if the parsed string does not represent a legal number.
Hence e.g. the fairly typical task of checking whether a string represents a number can be solved
with exception handling. The example program given below prints out for each command line parameter
whether the parameter represents a decimal number (that could be converted into a double
). The
working principle is simple: place the call of the string parsing function Double.parseDouble
into a try
block and define after it a catch
block for NumberFormatException
exceptions.
public class NumberParameters {
public static void main(String[] args) {
for(String arg : args) {
boolean isNumber = false;
try { // This code block can cause a NumberFormatException exception.
Double.parseDouble(arg); // Try to convert "arg" into a double.
isNumber = true; // This line will not be executed if an exception occurs!
}
catch(NumberFormatException e) {
} // Just catch the exception without doing anything: isNumber is still false.
System.out.format("The parameter \"%s\" %s a number.%n",
arg, (isNumber ? "is" : "is NOT"));
}
}
}
Executing this program as java NumberParameters one two 3.0 4 five 6
will output:
The parameter "one" is NOT a number.
The parameter "two" is NOT a number.
The parameter "3.0" is a number.
The parameter "4" is a number.
The parameter "five" is NOT a number.
The parameter "6" is a number.
Class library documentation usually describes what kind of exceptions, and under what circumstances, facilities provided by that library throw.