Example: Handling ArithmeticExceptions and InputMismatchExceptions

Example Handling ArithmeticExceptions and InputMismatchExceptions

The application in Fig. 13.2, which is based on Fig. 13.1, uses exception handling to process any ArithmeticExceptions and InputMistmatchExceptions that might arise. The application still prompts the user for two integers and passes them to method quotient, which calculates the quotient and returns an int result. This version of the application uses exception handling so that if the user makes a mistake, the program catches and handles (i.e., deals with) the exceptionin this case, allowing the user to try to enter the input again.

Figure 13.2. Handling ArithmeticExceptions and InputMismatchExceptions.

(This item is displayed on pages 643 - 644 in the print version)

1 // Fig. 13.2: DivideByZeroWithExceptionHandling.java 2 // An exception-handling example that checks for divide-by-zero. 3 import java.util.InputMismatchException; 4 import java.util.Scanner; 5 6 public class DivideByZeroWithExceptionHandling 7 { 8 // demonstrates throwing an exception when a divide-by-zero occurs 9 public static int quotient( int numerator, int denominator ) 10 throws ArithmeticException 11 { 12 return numerator / denominator; // possible division by zero 13 } // end method quotient 14 15 public static void main( String args[] ) 16 { 17 Scanner scanner = new Scanner( System.in ); // scanner for input 18 boolean continueLoop = true; // determines if more input is needed 19 20 do 21 { 22 try // read two numbers and calculate quotient 23 { 24 System.out.print( "Please enter an integer numerator: " ); 25 int numerator = scanner.nextInt(); 26 System.out.print( "Please enter an integer denominator: " ); 27 int denominator = scanner.nextInt(); 28 29 int result = quotient( numerator, denominator ); 30 System.out.printf( " Result: %d / %d = %d ", numerator, 31 denominator, result ); 32 continueLoop = false; // input successful; end looping 33 } // end try 34 catch ( InputMismatchException inputMismatchException ) 35 { 36 System.err.printf( " Exception: %s ", 37 inputMismatchException ); 38 scanner.nextLine(); // discard input so user can try again 39 System.out.println( 40 "You must enter integers. Please try again. " ); 41 } // end catch 42 catch ( ArithmeticException arithmeticException ) 43 { 44 System.err.printf( " Exception: %s ", arithmeticException ); 45 System.out.println( 46 "Zero is an invalid denominator. Please try again. " ); 47 } // end catch 48 } while ( continueLoop ); // end do...while 49 } // end main 50 } // end class DivideByZeroWithExceptionHandling  

Please enter an integer numerator: 100 Please enter an integer denominator: 7 Result: 100 / 7 = 14  

 

Please enter an integer numerator: 100 Please enter an integer denominator: 0 Exception: java.lang.ArithmeticException: / by zero Zero is an invalid denominator. Please try again. Please enter an integer numerator: 100 Please enter an integer denominator: 7 Result: 100 / 7 = 14  

 

Please enter an integer numerator: 100 Please enter an integer denominator: hello Exception: java.util.InputMismatchException You must enter integers. Please try again. Please enter an integer numerator: 100 Please enter an integer denominator: 7 Result: 100 / 7 = 14  

The first sample execution in Fig. 13.2 shows a successful execution that does not encounter any problems. In the second execution, the user enters a zero denominator and an ArithmeticException exception occurs. In the third execution, the user enters the string "hello" as the denominator, and an InputMismatchException occurs. For both exceptions, the user is informed of their mistake and asked to try again, then is prompted for two new integers. In each sample execution, the program runs successfully to completion.

Class InputMismatchException is imported in line 3. Class ArithmeticException does not need to be imported because it is located in package java.lang. Method main (lines 1549) creates a Scanner object at line 17. Line 18 creates the boolean variable continueLoop, which is true if the user has not yet entered valid input. Lines 2048 contain a do...while statement that repeatedly asks users for input until a valid input is received.

Enclosing Code in a try Block

Lines 2233 contain a try block, which encloses the code that might tHRow an exception and the code that should not execute if an exception occurs (i.e., if an exception occurs, the remaining code in the TRy block will be skipped). A TRy block consists of the keyword try followed by a block of code enclosed in curly braces ({}). [Note: The term "try block" sometimes refers only to the block of code that follows the TRy keyword (not including the try keyword itself). For simplicity, we use the term "try block" to refer to the block of code that follows the TRy keyword, as well as the try keyword.] The statements that read the integers from the keyboard (lines 25 and 27) each use method nextInt to read an int value. Method nextInt tHRows an InputMismatchException if the value read in is not a valid integer.

The division that can cause an ArithmeticException is not performed in the TRy block. Rather, the call to method quotient (line 29) invokes the code that attempts the division (line 12); the JVM throws an ArithmeticException object when the denominator is zero.

Software Engineering Observation 13.1

Exceptions may surface through explicitly mentioned code in a TRy block, through calls to other methods, through deeply nested method calls initiated by code in a try block or from the Java Virtual Machine as it executes Java bytecodes.

 

Catching Exceptions

The try block in this example is followed by two catch blocksone that handles an InputMismatchException (lines 3441) and one that handles an ArithmeticException (lines 4247). A catch block (also called a catch clause or exception handler) catches (i.e., receives) and handles an exception. A catch block begins with the keyword catch and is followed by a parameter in parentheses (called the exception parameter, discussed shortly) and a block of code enclosed in curly braces. [Note: The term "catch clause" is sometimes used to refer to the keyword catch followed by a block of code, where the term "catch block" refers to only the block of code following the catch keyword, but not including it. For simplicity, we use the term "catch block" to refer to the block of code following the catch keyword, as well as the keyword itself.]

At least one catch block or a finally block (discussed in Section 13.7) must immediately follow the try block. Each catch block specifies in parentheses an exception parameter that identifies the exception type the handler can process. When an exception occurs in a try block, the catch block that executes is the one whose type matches the type of the exception that occurred (i.e., the type in the catch block matches the thrown exception type exactly or is a superclass of it). The exception parameter's name enables the catch block to interact with a caught exception objecte.g., to implicitly invoke the caught exception's toString method (as in lines 37 and 44), which displays basic information about the exception. Line 38 of the first catch block calls Scanner method nextLine. Because an InputMismatchException occurred, the call to method nextInt never successfully read in the user's dataso we read that input with a call to method nextLine. We do not do anything with the input at this point, because we know that it is invalid. Each catch block displays an error message and asks the user to try again. After either catch block terminates, the user is prompted for input. We will soon take a deeper look at how this flow of control works in exception handling.

Common Programming Error 13.1

It is a syntax error to place code between a TRy block and its corresponding catch blocks.

Common Programming Error 13.2

Each catch block can have only a single parameterspecifying a comma-separated list of exception parameters is a syntax error.

Common Programming Error 13.3

It is a compilation error to catch the same type in two different catch blocks in a single try statement.

An uncaught exception is an exception that occurs for which there are no matching catch blocks. You saw uncaught exceptions in the second and third outputs of Fig. 13.1. Recall that when exceptions occurred in that example, the application terminated early (after displaying the exception's stack trace). This does not always occur as a result of uncaught exceptions. As you will learn in Chapter 23, Java uses a multithreaded model of program execution. Each thread is a parallel activity. One program can have many threads. If a program has only one thread, an uncaught exception will cause the program to terminate. If a program has multiple threads, an uncaught exception will terminate only the thread where the exception occurred. In such programs, however, certain threads may rely on others and if one thread terminates due to an uncaught exception, there may be adverse effects to the rest of the program.

Termination Model of Exception Handling

If an exception occurs in a try block (such as an InputMismatchException being thrown as a result of the code at line 25 of Fig. 13.2), the try block terminates immediately and program control transfers to the first of the following catch blocks in which the exception parameter's type matches the type of the thrown exception. In Fig. 13.2, the first catch block catches InputMismatchExceptions (which occur if invalid input is entered) and the second catch block catches ArithmeticExceptions (which occur if an attempt is made to divide by zero). After the exception is handled, program control does not return to the throw point because the try block has expired (which also causes any of its local variables to be lost). Rather control resumes after the last catch block. This is known as the termination model of exception handling. [Note: Some languages use the resumption model of exception handling, in which, after an exception is handled, control resumes just after the throw point.]

Common Programming Error 13.4

Logic errors can occur if you assume that after an exception is handled, control will return to the first statement after the throw point.

Error-Prevention Tip 13.2

With exception handling, a program can continue executing (rather than terminating) after dealing with a problem. This helps ensure the kind of robust applications that contribute to what is called mission-critical computing or business-critical computing.

Notice that we name our exception parameters (inputMismatchException and arithmeticException) based on their type. Java programmers often simply use the letter e as the name of their exception parameters.

Good Programming Practice 13.1

Using an exception parameter name that reflects the parameter's type promotes clarity by reminding the programmer of the type of exception being handled.

After executing a catch block, this program's flow of control proceeds to the first statement after the last catch block (line 48 in this case). The condition in the do...while statement is TRue (variable continueLoop contains its initial value of TRue), so control returns to the beginning of the loop and the user is once again prompted for input. This control statement will loop until valid input is entered. At that point, program control reaches line 32 which assigns false to variable continueLoop. The TRy block then terminates. If no exceptions are thrown in the TRy block, the catch blocks are skipped and control continues with the first statement after the catch blocks (or after the finally block, if one is present). Now the condition for the do...while loop is false, and method main ends.

The try block and its corresponding catch and/or finally blocks together form a try statement. It is important not to confuse the terms "try block" and "try statement"the term "try block" refers to the keyword try followed by a block of code, while the term "try statement" includes the try block, as well as the following catch blocks and/or finally block.

As with any other block of code, when a try block terminates, local variables declared in the block go out of scope (and are destroyed). When a catch block terminates, local variables declared within the catch block (including the exception parameter of that catch block) also go out of scope and are destroyed. Any remaining catch blocks in the try statement are ignored and execution resumes at the first line of code after the try...catch sequencethis will be a finally block, if one is present.

Using the throws Clause

Now let us examine method quotient (lines 913). The portion of the method declaration located at line 10 is known as a throws clause. A tHRows clause specifies the exceptions the method tHRows. This clause appears after the method's parameter list and before the method's body. The clause contains a comma-separated list of the exceptions that the method will throw if a problem occurs. Such exceptions may be thrown by statements in the method's body or by methods called in the body. A method can throw exceptions of the classes listed in its tHRows clause or of their subclasses. We have added the tHRows clause to this application to indicate to the rest of the program that this method may throw an ArithmeticException. Clients of method quotient are thus informed that the method may throw an ArithmeticException and that the exception should be caught. You will learn more about the tHRows clause in Section 13.6.

Error-Prevention Tip 13.3

If you know that a method might throw an exception, include appropriate exception-handling code in your program to make it more robust.

Error-Prevention Tip 13.4

Read the online API documentation for a method before using that method in a program. The documentation specifies the exceptions thrown by the method (if any) and indicates reasons why such exceptions may occur. Then provide for handling those exceptions in your program.

Error-Prevention Tip 13.5

Read the online API documentation for an exception class before writing exception-handling code for that type of exception. The documentation for an exception class typically contains potential reasons that such exceptions occur during program execution.

When line 12 executes, if the denominator is zero, the JVM throws an ArithmethicException object. This object will be caught by the catch block at lines 4247, which displays basic information about the exception by implicitly invoking the exception's toString method, then asks the user to try again.

If the denominator is not zero, method quotient performs the division and returns the result to the point of invocation of method quotient in the try block (line 29). Lines 3031 display the result of the calculation and line 32 sets continueLoop to false. In this case, the try block completes successfully, so the program skips the catch blocks, fails the condition at line 48 and method main completes execution normally.

Note that when quotient throws an ArithmeticException, quotient terminates and does not return a value, and quotient's local variables go out of scope (and the variables are destroyed). If quotient contained local variables that were references to objects and there are no other references to those object, would be marked for garbage collection. Also, when an exception occurs, the try block from which quotient was called terminates before lines 3032 can execute. Here, too, if local variables were created in the try block prior to the exception being thrown, these variables would go out of scope.

If an InputMismatchException is generated by lines 25 or 27, the TRy block terminates and execution continues with the catch block at lines 3441. In this case, method quotient is not called. Then method main continues after the last catch block (line 48).

Категории