Although you are just learning about them now, you have probably become well-acquainted with exceptions during the last 17 previous hours. These errors turn up when you write a Java program that compiles successfully but encounters a problem as it runs.
For example, a common programming mistake is to refer to an element of an array that doesn’t exist, as in the following statements:
String[] greek = { "Alpha", "Beta", "Gamma" };
System.out.println(greek[3]);
The String
array greek
has three elements. Because the first element of an array is numbered 0 rather than 1, the first element is greek[0]
, the second greek[1]
, and the third greek[2]
. So the statement attempting to display greek[3]
is erroneous. The preceding statements compile successfully, but when you run the program, the Java interpreter halts with a message such as the following:
Exception in thread "main" java.lang.ArrayIndexOutBoundsException: 3
at SampleProgram.main(SampleProgram.java:4)
This message indicates that the application has generated an exception, which the interpreter noted by displaying an error message and stopping the program.
The error message refers to a class called ArrayIndexOutOfBoundsException
in the java.lang
package. This class is an exception, an object that represents an exceptional circumstance that has taken place in a Java program.
When a Java class encounters an exception, it alerts users of the class to the error. In this example, the user of the class is the Java interpreter.
Two terms are used to describe this process: throw and catch. Objects throw exceptions to alert others that they have occurred. These exceptions are caught by other objects or the Java interpreter.
All exceptions are subclasses of Exception
in the java.lang
package. The ArrayIndexOutOfBoundsException
does what you would expect—it reports that an array element has been accessed outside the array’s boundaries.
There are hundreds of exceptions in Java. Many such as the array exception indicate a problem that can be fixed with a programming change. These are comparable to compiler errors—after you correct the situation, you don’t have to concern yourself with the exception any longer.
Other exceptions must be dealt with every time a program runs by using five new keywords: try
, catch
, finally
, throw
, and throws
.
try
-catch
BlockUp to this point, you have dealt with exceptions by fixing the problem that caused them. There are times you can’t deal with an exception in that manner and must handle the issue within a Java class.
As an introduction to why this is useful, enter the short Java application in Listing 18.1 in a new empty Java file called Calculator
and save the file.
1: public class Calculator {
2: public static void main(String[] arguments) {
3: float sum = 0;
4: for (int i = 0; i < arguments.length; i++) {
5: sum = sum + Float.parseFloat(arguments[i]);
6: }
7: System.out.println("Those numbers add up to " + sum);
8: }
9: }
The Calculator
application takes one or more numbers as command-line arguments, adds them up, and displays the total.
Because all command-line arguments are represented by strings in a Java application, the program must convert them into floating-point numbers before adding them together. The Float.parseFloat()
class method in Line 5 takes care of this, adding the converted number to a variable named sum
.
Before running the application with the following command-line arguments, which can be set in NetBeans with the Run, Set Project Configuration, Customize command: 8 6 7 5 3 0 9
. Choose Run, Run Main Project to run the application and see the output in Figure 18.1.
Run the program several times with different numbers as arguments. It should handle them successfully, which might make you wonder what this has to do with exceptions.
To see the relevance, change the Calculator
application’s command-line arguments to 1 3 5x
.
The third argument contains a typo—there shouldn’t be an x
after the number 5. The Calculator
application has no way to know this is a mistake, so it tries to add 5x
to the other numbers, causing the following exception to be displayed:
Exception in thread "main" java.lang.NumberFormatException: For input
string: "5x" at sun.misc.FloatingDecimal.readJavaFormatString
(FloatingDecimal.java:1224)
at java.lang.Float.parseFloat(Float.java:422)
at Calculator.main(Calculator.java:5)
This message can be informative to a programmer, but it’s not something you’d want a user to see. Java programs can take care of their own exceptions by using a try
-catch
block statement, which takes the following form:
try {
// statements that might cause the exception
} catch (Exception e) {
// what to do when the exception occurs
}
A try
-catch
block must be used on any exception that you want a method of a class to handle. The Exception
object that appears in the catch
statement should be one of three things:
• The class of the exception that might occur
• More than one class of exception, separated by | characters
• A superclass of several different exceptions that might occur
The try
section of the try
-catch
block contains the statement (or statements) that might throw an exception. In the Calculator
application, the call to the Float.parseFloat(
String)
method in Line 5 of Listing 18.1 throws a NumberFormatException
whenever it is used with a string argument that can’t be converted to a floating-point value.
To improve the Calculator
application so that it never stops running with this kind of error, you can use a try
-catch
block.
Create a new empty Java file called NewCalculator
and enter the text of Listing 18.2.
1: public class NewCalculator {
2: public static void main(String[] arguments) {
3: float sum = 0;
4: for (int i = 0; i < arguments.length; i++) {
5: try {
6: sum = sum + Float.parseFloat(arguments[i]);
7: } catch (NumberFormatException e) {
8: System.out.println(arguments[i] + " is not a number.");
9: }
10: }
11: System.out.println("Those numbers add up to " + sum);
12: }
13: }
After you save the application, run it with the command-line argument 1 3 5x
and you see the output shown in Figure 18.2.
The try
-catch
block in Lines 5–9 deals with NumberFormatException
errors thrown by Float.parseFloat()
. These exceptions are caught within the NewCalculator
class, which displays an error message for any argument that is not a number. Because the exception is handled within the class, the Java interpreter does not display an error. You can often deal with problems related to user input and other unexpected data by using try
-catch
blocks.
A try
-catch
block can be used to handle several different kinds of exceptions, even if they are thrown by different statements.
One way to handle multiple classes of exceptions is to devote a catch
block to each one, as in this code:
String textValue = "35";
int value;
try {
value = Integer.parseInt(textValue);
catch (NumberFormatException exc) {
// code to handle exception
} catch (Arithmetic Exception exc) {
// code to handle exception
}
As of Java 7, you also can handle multiple exceptions in the same catch
block by separating them with pipe (|) characters and ending the list with a name for the exception variable. Here’s an example:
try {
value = Integer.parseInt(textValue);
catch (NumberFormatException | Arithmetic Exception exc) {
// code to handle exceptions
}
If a NumberFormatException
or ArithmeticException
is caught, it will be assigned to the exc
variable.
Listing 18.3 contains an application called NumberDivider
that takes two integer arguments from the command-line and uses them in a division expression.
This application must be able to deal with two potential problems in user input:
• Nonnumeric arguments
• Division by zero
Create a new empty Java file for NumberDivider
and enter the text of Listing 18.3 into the source editor.
1: public class NumberDivider {
2: public static void main(String[] arguments) {
3: if (arguments.length == 2) {
4: int result = 0;
5: try {
6: result = Integer.parseInt(arguments[0]) /
7: Integer.parseInt(arguments[1]);
8: System.out.println(arguments[0] + " divided by " +
9: arguments[1] + " equals " + result);
10: } catch (NumberFormatException e) {
11: System.out.println("Both arguments must be numbers.");
12: } catch (ArithmeticException e) {
13: System.out.println("You cannot divide by zero.");
14: }
15: }
16: }
17: }
Using command-line arguments to specify two arguments, you can run it with integers, floating-point numbers, and nonnumeric arguments.
The if
statement in Line 3 checks to make sure that two arguments are sent to the application. If not, the program exits without displaying anything.
The NumberDivider
application performs integer division, so the result is an integer. In integer division, 5 divided by 2 equals 2, not 2.5.
If you use a floating-point or nonnumeric argument, a NumberFormatException
is thrown by Lines 6–7 and caught by Lines 10–11.
If you use an integer as the first argument and a zero as the second argument, a ArithmeticExpression
is thrown in Lines 6–7 and caught by Lines 12–13.
When you are dealing with multiple exceptions by using try
and catch
, there are times when you want the program to do something at the end of the block whether an exception occurred or not.
You can handle this by using a try
-catch
-finally
block, which takes the following form:
try {
// statements that might cause the exception
} catch (Exception e) {
// what to do when the exception occurs
} finally {
// statements to execute no matter what
}
The statement or statements within the finally
section of the block is executed after everything else in the block, even if an exception occurs.
One place this is useful is in a program that reads data from a file on disk, which you do in Hour 20, “Reading and Writing Files.” There are several ways an exception can occur when you are accessing data—the file might not exist, a disk error could occur, and so on. If the statements to read the disk are in a try
section and errors are handled in a catch
section, you can close the file in the finally
section. This makes sure that the file is closed whether or not an exception is thrown as it is read.
3.144.16.152