1 / 39

Chapter 14 - Exception Handling

2. Using try and catch Blocks to Handle "Dangerous" Method Calls. Some API method calls are "dangerous" in that they might possibly lead to a runtime error.Example of a "safe" API method call (no runtime error possible):System.out.println(<expression>)Example of an API method call that might lead

jesse
Download Presentation

Chapter 14 - Exception Handling

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


    1. 1 Chapter 14 - Exception Handling Using try and catch Blocks to Handle "Dangerous" Method Calls NumberFormatException Line Plot Example try and catch Blocks - More Details Two Types of Exceptions - Checked and Unchecked Unchecked Exceptions Checked Exceptions Using API Documentation when Writing Exception-Handling Code When a try Block Throws Different Types of Exceptions The Exception Class and its getMessage Method Multiple catch blocks Understanding Exception Messages 1. In this chapter I demo these files: LinePlot.java CreateNewFile.java PrintCharFromFile.java PrintCharFromFile2.java1. In this chapter I demo these files: LinePlot.java CreateNewFile.java PrintCharFromFile.java PrintCharFromFile2.java

    2. 2 Using try and catch Blocks to Handle "Dangerous" Method Calls Some API method calls are "dangerous" in that they might possibly lead to a runtime error. Example of a "safe" API method call (no runtime error possible): System.out.println(<expression>) Example of an API method call that might lead to a runtime error: Integer.parseInt(<string>) Technique for handling such runtime errors: Use exception handling. More specifically, surround the method call with a try block and insert a catch block immediately after the try block. 1. "dangerous" is not a standard term, but I like to use the term because it helps with the explanation. 2. By the way: System is a class. out is a class variable in the System class. println is a method in out's PrintStream class. 3. When would the parseInt method call lead to an error? If the string argument was not a valid integer (to be valid, it needs to contain all digits). Use a try-catch mechanism to be safe and to validate that the call worked.1. "dangerous" is not a standard term, but I like to use the term because it helps with the explanation. 2. By the way: System is a class. out is a class variable in the System class. println is a method in out's PrintStream class. 3. When would the parseInt method call lead to an error? If the string argument was not a valid integer (to be valid, it needs to contain all digits). Use a try-catch mechanism to be safe and to validate that the call worked.

    3. 3 Using try and catch Blocks to Handle "Dangerous" Method Calls Syntax for try and catch blocks: try { <statement(s)> } catch (<exception-class> <parameter>) { <error-handling-code> } Example try and catch code fragment: try { quantity = Integer.parseInt(userEntry); } catch (NumberFormatException nfe) { System.out.println("Invalid quantity entered." + " Must be a whole number."); } 1. I read the boxes. Try and catch are pretty good names - use a try block to "try" out some dangerous code. If there's a problem with the dangerous code, then the catch block "catches" the problem. 2. Note how the example follows the syntax pattern. We're keeping things simple for this first example and using only a single statement inside our try block. NumberFormatException is an exception class and it does match the type of exception that the try block might throw. In other words, the parseInt method might throw a NumberFormatException exception. 3. Review: What type of variable is userEntry? A string! What type of variable is quantity? An int!1. I read the boxes. Try and catch are pretty good names - use a try block to "try" out some dangerous code. If there's a problem with the dangerous code, then the catch block "catches" the problem. 2. Note how the example follows the syntax pattern. We're keeping things simple for this first example and using only a single statement inside our try block. NumberFormatException is an exception class and it does match the type of exception that the try block might throw. In other words, the parseInt method might throw a NumberFormatException exception. 3. Review: What type of variable is userEntry? A string! What type of variable is quantity? An int!

    4. 4 Using try and catch Blocks to Handle "Dangerous" Method Calls Semantics for previous slide's try and catch code fragment: If the userEntry string contains all digits, then: quantity gets the int version of userEntry. The JVM skips the catch block and continues below it. If the userEntry string does not contain all digits, then: The parseInt method throws a NumberFormatException object. The JVM looks for a catch block that will catch the thrown exception object; i.e., it looks for a matching catch block. If it finds one, it executes it and continues below the catch block. If there's no matching catch block, the program crashes. 1. I'll show a complete program example coming up and you'll see how the JVM continues below the catch block. 2. What's a matching catch block? A catch block is "matching" if the catch heading's parameter matches the type of the thrown exception. I show on the previous slide: The NumberFormatException parameter matches the NumberFormatException thrown by the parseInt method call. So the NumberFormatException parameter's catch block is a matching catch block if and when the parseInt method call throws a NumberFormatException.1. I'll show a complete program example coming up and you'll see how the JVM continues below the catch block. 2. What's a matching catch block? A catch block is "matching" if the catch heading's parameter matches the type of the thrown exception. I show on the previous slide: The NumberFormatException parameter matches the NumberFormatException thrown by the parseInt method call. So the NumberFormatException parameter's catch block is a matching catch block if and when the parseInt method call throws a NumberFormatException.

    5. 5 NumberFormatException The NumberFormatException is well named because it's thrown when a number's format is inappropriate. More specifically, it's thrown by one of the parse methods (Integer.parseInt, Long.parseLong, Double.parseDouble, etc.) when there's an attempt to convert a string to a number and the string's characters don't form a valid number. These code fragments throw NumberFormatExceptions: int numOfPages = Integer.parseInt("962.0"); double height = Double.parseDouble("1.76m"); 1. So far, we've mentioned only one type of exception, the NumberFormatException. We'll cover other exceptions later on, but for now, a little more detail on the NumberFormatException…1. So far, we've mentioned only one type of exception, the NumberFormatException. We'll cover other exceptions later on, but for now, a little more detail on the NumberFormatException…

    6. 6 Line Plot Example This program plots a line by reading in a series of point coordinate positions. It works fine as long as the user enters valid input. But with invalid input, the program crashes. Add code so as to avoid those crashes. import java.util.Scanner; public class LinePlot { private int oldX = 0; // oldX, oldY save the previous point private int oldY = 0; // The starting point is the origin (0,0) //************************************************************* // This method prints a line segment from the previous point // to the current point. public void plotSegment(int x, int y) { System.out.println("New segment = (" + oldX + "," + oldY + ")-(" + x + "," + y + ")"); oldX = x; oldY = y; } // end plotSegment 1. Now I'll show how this try and catch stuff is used in a complete program…. 2. The best way to get a handle on what this program does is to demo it. I demo the commented-out-exception-handling-code version of LinePlot.java. When prompted for x & y, I enter 3 <space> 1 and show the output. Note that the plotSegment method is very primitive; it uses text to represent the segment. In a real line-plotting program, you'd use Java's lineDraw method to display an actual line instead of a textual description of a line. You can see how that's done by reading the optional GUI section at the end of Chapter 14. 3. The plotSegment method prints the segment message as shown in the demo. I write this example on the board: (0,0)-(3,1) The 0,0 is the old point (see top of class) and the 3,1 is the just-entered point. After printing the segment, we save the just-entered point (x and y) in the oldX and oldY variables so we can use them for the next segment that gets plotted. I continue the demo by entering 2 <space> 2 and then q.1. Now I'll show how this try and catch stuff is used in a complete program…. 2. The best way to get a handle on what this program does is to demo it. I demo the commented-out-exception-handling-code version of LinePlot.java. When prompted for x & y, I enter 3 <space> 1 and show the output. Note that the plotSegment method is very primitive; it uses text to represent the segment. In a real line-plotting program, you'd use Java's lineDraw method to display an actual line instead of a textual description of a line. You can see how that's done by reading the optional GUI section at the end of Chapter 14. 3. The plotSegment method prints the segment message as shown in the demo. I write this example on the board: (0,0)-(3,1) The 0,0 is the old point (see top of class) and the 3,1 is the just-entered point. After printing the segment, we save the just-entered point (x and y) in the oldX and oldY variables so we can use them for the next segment that gets plotted. I continue the demo by entering 2 <space> 2 and then q.

    7. 7 Line Plot Example //************************************************************* public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); LinePlot line = new LinePlot(); String xStr, yStr; // coordinates for a point (String form) int x, y; // coordinates for a point System.out.print("Enter x & y coordinates (q to quit): "); xStr = stdIn.next(); while (!xStr.equalsIgnoreCase("q")) { yStr = stdIn.next(); x = Integer.parseInt(xStr); y = Integer.parseInt(yStr); line.plotSegment(x, y); System.out.print("Enter x & y coordinates (q to quit): "); xStr = stdIn.next(); } // end while } // end main } // end class LinePlot 1. Read in x and y coordinate positions. Read the stdIn.next note. 2. Continue to read in point coordinates until the user enters "q." In the past, when we entered numbers inside a loop, we oftentimes terminated the loop with a numeric sentinel value. This is a more elegant implementation because it allows a non-numeric "q" as the sentinel value. 3. How can we read in numbers and the string "q" with the same input statement? Read the user input as a string and then if the string is not a "q," convert it to a number using Integer.parseInt! 4. Inside the loop, we call the plotSegment method; as you know, it draws a line from the previous point to the just-entered point. 5. This implementation works OK as long as the user only enters numbers and "q." What happens when the user enters something else? 6. I demo the commented-out-exception-handling-code version of LinePlot.java. I enter an invalid value and watch the crash.1. Read in x and y coordinate positions. Read the stdIn.next note. 2. Continue to read in point coordinates until the user enters "q." In the past, when we entered numbers inside a loop, we oftentimes terminated the loop with a numeric sentinel value. This is a more elegant implementation because it allows a non-numeric "q" as the sentinel value. 3. How can we read in numbers and the string "q" with the same input statement? Read the user input as a string and then if the string is not a "q," convert it to a number using Integer.parseInt! 4. Inside the loop, we call the plotSegment method; as you know, it draws a line from the previous point to the just-entered point. 5. This implementation works OK as long as the user only enters numbers and "q." What happens when the user enters something else? 6. I demo the commented-out-exception-handling-code version of LinePlot.java. I enter an invalid value and watch the crash.

    8. 8 Line Plot Example (hidden) while (!xStr.equalsIgnoreCase("q")) { yStr = stdIn.next(); try { x = Integer.parseInt(xStr); y = Integer.parseInt(yStr); line.plotSegment(x, y); } catch (NumberFormatException nfe) { System.out.println("Invalid entry." + " Must enter integer space integer."); } System.out.print("Enter x & y coordinates (q to quit): "); xStr = stdIn.next(); } // end while 1. Let's rewrite the while loop on the previous slide so that it includes input validation using a try-catch mechanism. [I should draw the solution on the board rather than enter it on the computer because: If we fix the program on the computer, when we make the first fix of surrounding only the two parseInt lines with a try block, there would be an error message "Variables x and y may not have been initialized" that I want to avoid for now. That error message would lead me to initialize x and y to 0 and that's not really necessary after the plotSegment call is moved into the try block.] 2. In looking at the previous slide, I ask "Where is the dangerous code?" After they identify the two parseInt method calls, I suggest surrounding them with a try block and inserting a catch block after the try block. I write the above code except that line.plotSegment(x, y); is below the catch block. 3. Any problems? What happens if there's invalid input? A NumberFormatException object is thrown, and then caught, and then an error message is printed. And then line.plotSegment executes. We don't want to print the line segment if the input values are messed up. 4. What's the solution? Move the line.plotSegment(x, y); line to the last line in the try block. Then, it gets executed only if the two parseInt method calls work properly.1. Let's rewrite the while loop on the previous slide so that it includes input validation using a try-catch mechanism. [I should draw the solution on the board rather than enter it on the computer because: If we fix the program on the computer, when we make the first fix of surrounding only the two parseInt lines with a try block, there would be an error message "Variables x and y may not have been initialized" that I want to avoid for now. That error message would lead me to initialize x and y to 0 and that's not really necessary after the plotSegment call is moved into the try block.] 2. In looking at the previous slide, I ask "Where is the dangerous code?" After they identify the two parseInt method calls, I suggest surrounding them with a try block and inserting a catch block after the try block. I write the above code except that line.plotSegment(x, y); is below the catch block. 3. Any problems? What happens if there's invalid input? A NumberFormatException object is thrown, and then caught, and then an error message is printed. And then line.plotSegment executes. We don't want to print the line segment if the input values are messed up. 4. What's the solution? Move the line.plotSegment(x, y); line to the last line in the try block. Then, it gets executed only if the two parseInt method calls work properly.

    9. 9 try and catch Blocks - More Details Deciding on the size of your try blocks is a bit of an art. Sometimes it's better to use small try blocks and sometimes it's better to use larger try blocks. Note that it's legal to surround an entire method body with a try block, but that's usually counterproductive because it makes it harder to identify the "dangerous" code. In general, you should make your try blocks small so that your "dangerous" code is more obvious. However, if a chunk of code has several "dangerous" method/constructor calls: Adding a separate try-catch structure for each such call might result in cluttered code. To improve program readability, consider using a single try block that surrounds the calls. 1. That's what we did with the LinePlot program.1. That's what we did with the LinePlot program.

    10. 10 try and catch Blocks - More Details In our LinePlot program solution, we surrounded the two parseInt statements with a single try block because they were conceptually related and physically close together. We also included the line.plotSegment() call within that same try block. Why? Our single try block solution is perfectly acceptable, but wouldn't it be nice to have a more specific message that identified which entry was invalid (x, y, or both)?. To have that sort of message, you'd have to have a separate try-catch structure for each parseInt statement. 1. So that it would be executed only if the two parseInt statements worked. 2. Can you think of a possible improvement for the LinePlot program's error message? I go back to the program slide and look at the generic error message. 3. There's an end-of-chapter exercise that asks you to do that. [In addition to requiring code for a second try block, it also requires the use of a boolean variable to keep track of whether there's been an error.]1. So that it would be executed only if the two parseInt statements worked. 2. Can you think of a possible improvement for the LinePlot program's error message? I go back to the program slide and look at the generic error message. 3. There's an end-of-chapter exercise that asks you to do that. [In addition to requiring code for a second try block, it also requires the use of a boolean variable to keep track of whether there's been an error.]

    11. 11 try and catch Blocks - More Details If an exception is thrown, the JVM immediately jumps out of the current try block and looks for a matching catch block. The immediacy of the jump means that if there are statements in the try block after the exception-throwing statement, those statements are skipped. The compiler is a pessimist. It knows that anything inside a try block might possibly be skipped, and it assumes the worst; i.e., it assumes that all statements inside a try block get skipped. Consequently, if there's a try block that contains an assignment for x, the compiler assumes that the assignment is skipped. If there's no assignment for x outside of the try block and x's value is needed outside of the try block, you'd get this compilation error: variable x might not have been initialized If you get that error, you can usually fix it by initializing the variable prior to the try block. 1. I'll show you an example shortly. 2. I'll show you an example on the next slide….1. I'll show you an example shortly. 2. I'll show you an example on the next slide….

    12. 12 try and catch Blocks - More Details This method reads a value from a user, makes sure it's an integer, and returns it. Note the compilation errors. What are the fixes? public static int getIntFromUser() { Scanner stdIn = new Scanner(System.in); String xStr; // user entry boolean valid; // is user entry a valid integer? int x; // integer form of user entry System.out.print("Enter an integer: "); xStr = stdIn.next(); do { try { valid = false; x = Integer.parseInt(xStr); valid = true; } catch (NumberFormatException nfe) { System.out.print("Invalid entry. Enter an integer: "); xStr = stdIn.next(); } } while (!valid); return x; } // end getIntFromUser 1. I walk through the code and when I come to the try block: Note the first line: valid = false; We start by assuming valid is false. 2. If the parseInt is successful, the JVM continues down to the valid = true line. The JVM skips the catch block and checks the do loop condition. Since valid is true, the !valid condition is false and the do loop terminates. 3. If the parseInt throws an exception, the JVM skips the valid = true line and jumps to the catch block. After finishing the catch block, the JVM checks the do loop condition. Since valid is false, the !valid condition is true and the do loop continues. 4. What are the compilation errors? I read the boxes. 5. Why does the compiler think valid might not have been initialized? Because the only place valid is assigned a value is inside the try. Even though we know that the valid = false statement is in no actual danger of being skipped (it's a simple assignment and it's the first line in the try block), the compiler still assumes that it gets skipped. 6. What's the solution? Move the valid = false assignment up to valid's declaration line. 7. Why does the compiler think x might not have been initialized? Because the only place x is assigned a value is inside the try and the compiler assumes that try stuff gets skipped. 8. What's the solution? Initialize x to 0 at the top of the method.1. I walk through the code and when I come to the try block: Note the first line: valid = false; We start by assuming valid is false. 2. If the parseInt is successful, the JVM continues down to the valid = true line. The JVM skips the catch block and checks the do loop condition. Since valid is true, the !valid condition is false and the do loop terminates. 3. If the parseInt throws an exception, the JVM skips the valid = true line and jumps to the catch block. After finishing the catch block, the JVM checks the do loop condition. Since valid is false, the !valid condition is true and the do loop continues. 4. What are the compilation errors? I read the boxes. 5. Why does the compiler think valid might not have been initialized? Because the only place valid is assigned a value is inside the try. Even though we know that the valid = false statement is in no actual danger of being skipped (it's a simple assignment and it's the first line in the try block), the compiler still assumes that it gets skipped. 6. What's the solution? Move the valid = false assignment up to valid's declaration line. 7. Why does the compiler think x might not have been initialized? Because the only place x is assigned a value is inside the try and the compiler assumes that try stuff gets skipped. 8. What's the solution? Initialize x to 0 at the top of the method.

    13. 13 Two Types of Exceptions - Checked and Unchecked There are two types of exceptions – checked and unchecked. Checked exceptions are required to be checked with a try-catch mechanism. Unchecked exceptions are not required to be checked with a try-catch mechanism (but, as an option, unchecked exceptions may be checked with a try-catch mechanism). How can you tell whether a particular exception is classified as checked or unchecked? To find out if a particular exception is checked or unchecked, look up its associated class in the API documentation. On the class's API page, look at its class hierarchy tree. If you find that the class is derived from the RuntimeExeption class or from the Error exception class, then it's an unchecked exception. Otherwise, it's a checked exception. 1. I go to Sun's API documentation web site and look up NumberFormatException. Find it's ancestors and note that RunTimeException is there. That tells us that the NumberFormatException class is an unchecked exception.1. I go to Sun's API documentation web site and look up NumberFormatException. Find it's ancestors and note that RunTimeException is there. That tells us that the NumberFormatException class is an unchecked exception.

    14. 14 Two Types of Exceptions - Checked and Unchecked 1. Here's the class hierarchy for all exceptions. 2. Note the RuntimeException class and the Error class. They're the ancestor classes for all unchecked exception classes. I read the text under the Error class. There's not a whole lot you can do about Error class exceptions, so don't worry about them. 3. But you can do something about exceptions derived from the RuntimeException class, and you'll deal with them a lot. When you see an exception that's derived from the RuntimeException class, you'll know it's an unchecked exception. Note that NumberFormatException is an unchecked exception. I read the green box. 4. So when you call parseInt, does the compiler force you to surround the call with a try block? No - parseInt throws an unchecked exception, so the try-catch mechanism is optional. That should make sense since we used parseInt prior to this chapter and we never used a try-catch mechanism. 5. Note that all checked exceptions are derived from the Exception class, and not from the RuntimeException class or the Error class. We'll cover checked exceptions a bit later. First let's talk about unchecked exceptions in detail....1. Here's the class hierarchy for all exceptions. 2. Note the RuntimeException class and the Error class. They're the ancestor classes for all unchecked exception classes. I read the text under the Error class. There's not a whole lot you can do about Error class exceptions, so don't worry about them. 3. But you can do something about exceptions derived from the RuntimeException class, and you'll deal with them a lot. When you see an exception that's derived from the RuntimeException class, you'll know it's an unchecked exception. Note that NumberFormatException is an unchecked exception. I read the green box. 4. So when you call parseInt, does the compiler force you to surround the call with a try block? No - parseInt throws an unchecked exception, so the try-catch mechanism is optional. That should make sense since we used parseInt prior to this chapter and we never used a try-catch mechanism. 5. Note that all checked exceptions are derived from the Exception class, and not from the RuntimeException class or the Error class. We'll cover checked exceptions a bit later. First let's talk about unchecked exceptions in detail....

    15. 15 Unchecked Exceptions As you know, unchecked exceptions are not required to be checked with a try-catch mechanism. However, at runtime, if an unchecked exception is thrown and not caught, then the program will crash (terminate ungracefully). How to handle code that might throw an unchecked exception: Use a try-catch mechanism (see GetIntFromUser method). or Don't attempt to catch the exception, but write the code carefully so as to avoid the possibility of the exception being thrown (see upcoming example). 1. Note that both of these techniques are used in industry. We'll illustrate both of these techniques with an example that starts on the next slide….1. Note that both of these techniques are used in industry. We'll illustrate both of these techniques with an example that starts on the next slide….

    16. 16 Unchecked Exceptions The following method attempts to remove a specified student from a list of student names. The list of student names is stored in an ArrayList instance variable named students. public void removeStudent(int index) { students.remove(index); } // end removeStudent The students.remove method call is dangerous because it throws an unchecked exception, IndexOutOfBoundsException, if its argument holds an invalid index. On the upcoming slides, we address that problem by providing improved versions of the removeStudent method. 1. Remember the remove method in the ArrayList class? You pass it the index of the element you want to delete. 2. What are the two strategies for addressing unchecked exceptions? Use a try-catch mechanism or write careful code!1. Remember the remove method in the ArrayList class? You pass it the index of the element you want to delete. 2. What are the two strategies for addressing unchecked exceptions? Use a try-catch mechanism or write careful code!

    17. 17 Unchecked Exceptions Improved removeStudent method using a try-catch mechanism: public void removeStudent(int index) { try { students.remove(index); } catch (IndexOutOfBoundsException e) { System.out.println( "Can't remove student because " + index + " is an invalid index position."); } } // end removeStudent 1. I walk through the code.1. I walk through the code.

    18. 18 Unchecked Exceptions Improved removeStudent method, using careful code: public void removeStudent(int index) { if (index >= 0 && index < students.size()) { students.remove(index); } else { System.out.println( "Can't remove student because " + index + " is an invalid index position."); } } // end removeStudent 1. I walk through the code. 2. So which solution is better - the try-catch solution or this solution? The solutions are about the same in terms of readability. With things being equal in terms of readability, go with the careful-code implementation because it's more efficient. Exception-handling code is fairly inefficient because to throw an exception, the JVM has to instantiate an exception object and find a matching catch block. 3. We're now done with our discussion of unchecked exceptions. Let's now discuss checked exceptions….1. I walk through the code. 2. So which solution is better - the try-catch solution or this solution? The solutions are about the same in terms of readability. With things being equal in terms of readability, go with the careful-code implementation because it's more efficient. Exception-handling code is fairly inefficient because to throw an exception, the JVM has to instantiate an exception object and find a matching catch block. 3. We're now done with our discussion of unchecked exceptions. Let's now discuss checked exceptions….

    19. 19 Checked Exceptions If a code fragment has the potential of throwing a checked exception, then the compiler requires that the code fragment has an associated try-catch mechanism. If there is no associated try-catch mechanism, then the compiler generates an error. The program on the next slide contains code that might possibly throw a checked exception and there's no try-catch mechanism. Thus, it generates a compilation error. What code should be added to fix the program? [1. To "associate a code fragment with a try-catch mechanism," put the code fragment 1) inside a try block or 2) inside a method that declares a throws clause in its heading so that an exception can be passed back to the original calling method. We'll describe the throws clause later.] 2. With unchecked exceptions, you had a choice of how to handle them - try-catch mechanism or careful code. With checked exceptions, there's no choice - you must use a try-catch mechanism.[1. To "associate a code fragment with a try-catch mechanism," put the code fragment 1) inside a try block or 2) inside a method that declares a throws clause in its heading so that an exception can be passed back to the original calling method. We'll describe the throws clause later.] 2. With unchecked exceptions, you had a choice of how to handle them - try-catch mechanism or careful code. With checked exceptions, there's no choice - you must use a try-catch mechanism.

    20. 20 import java.util.Scanner; import java.io.File; import java.io.IOException; public class CreateNewFile { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); String fileName; // user-specified file name File file; System.out.print("Enter file to be created: "); fileName = stdIn.nextLine(); file = new File(fileName); if (file.exists()) { System.out.println("Sorry, can't create that file. It already exists."); } else { file.createNewFile(); System.out.println(fileName + " created."); } } // end main } // end CreateNewFile class Checked Exceptions 1. I read the program-synopsis box. 2. File I/O is covered in the next chapter, chapter 16. You're not responsible for the file details in this example, just the exception-handling details. So why use a file example prior to the files chapter? Because we wanted a good checked exception example and file programs provide for that. It would make more sense to use previously covered material for our checked exception example, but that wasn't really an option. Our previously covered commands don't throw checked exceptions. I walk through the program's code. 3. I read the next two non-hidden slides and return here. 4. Note the three API constructor/method calls. For each call, I look it up in the API documentation and figure out how to handle it: a) File constructor call - throws an unchecked NullPointerException if its argument is null. The code is written so that there's no danger of fileName being null, so there's no need to add any code for the File constructor call. b) exists method call - throws an unchecked SecurityException if a security manager exists. Since we don't have a security manager, there's no need to add any code for the exists method call. c) createNewFile method call - throws a checked IOException if there's an I/O problem, like a corrupt hard disk or an invalid directory name. We'll need to add a try-catch structure to handle the checked exception, but first let's compile the program as is. 5. I load CreateNewFile.java into a compiler, compile it, and view the IOException error on the createNewFile line. Note that the other two API calls did not generate compilation errors because those calls throw unchecked exceptions.1. I read the program-synopsis box. 2. File I/O is covered in the next chapter, chapter 16. You're not responsible for the file details in this example, just the exception-handling details. So why use a file example prior to the files chapter? Because we wanted a good checked exception example and file programs provide for that. It would make more sense to use previously covered material for our checked exception example, but that wasn't really an option. Our previously covered commands don't throw checked exceptions. I walk through the program's code. 3. I read the next two non-hidden slides and return here. 4. Note the three API constructor/method calls. For each call, I look it up in the API documentation and figure out how to handle it: a) File constructor call - throws an unchecked NullPointerException if its argument is null. The code is written so that there's no danger of fileName being null, so there's no need to add any code for the File constructor call. b) exists method call - throws an unchecked SecurityException if a security manager exists. Since we don't have a security manager, there's no need to add any code for the exists method call. c) createNewFile method call - throws a checked IOException if there's an I/O problem, like a corrupt hard disk or an invalid directory name. We'll need to add a try-catch structure to handle the checked exception, but first let's compile the program as is. 5. I load CreateNewFile.java into a compiler, compile it, and view the IOException error on the createNewFile line. Note that the other two API calls did not generate compilation errors because those calls throw unchecked exceptions.

    21. 21 import java.util.Scanner; import java.io.File; import java.io.IOException; public class CreateNewFile { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); String fileName; // user-specified file name File file; System.out.print("Enter file to be created: "); fileName = stdIn.nextLine(); file = new File(fileName); if (file.exists()) { System.out.println("Sorry, can't create that file. It already exists."); } else { file.createNewFile(); System.out.println(fileName + " created."); } } // end main } // end CreateNewFile class Checked Exceptions (hidden) 1. What's the fix? I coax the students into entering this in the compiler (and I emphasize that the "created" print statement needs to be inside the try block). try { file.createNewFile(); System.out.println(fileName + " created."); } catch (IOException ioe) { System.out.println("File I/O error"); } 2. I demo CreateNewFile.java by running it four times with these user entries: a) junk.txt (depending on the PC's configuration, I might have to enter a full path so that the file is saved in an appropriate directory) b) junk.txt (note the exists error message) c) <full path>/junk2.txt (Java allows / for path directory separators. On Windows PCs, \ also works.) d) <invalid path>/junk2.txt (note the File I/O error message)1. What's the fix? I coax the students into entering this in the compiler (and I emphasize that the "created" print statement needs to be inside the try block). try { file.createNewFile(); System.out.println(fileName + " created."); } catch (IOException ioe) { System.out.println("File I/O error"); } 2. I demo CreateNewFile.java by running it four times with these user entries: a) junk.txt (depending on the PC's configuration, I might have to enter a full path so that the file is saved in an appropriate directory) b) junk.txt (note the exists error message) c) <full path>/junk2.txt (Java allows / for path directory separators. On Windows PCs, \ also works.) d) <invalid path>/junk2.txt (note the File I/O error message)

    22. 22 Using API Documentation when Writing Exception-Handling Code Whenever you want to use a method or constructor from one of the API classes and you're not sure about it, you should look it up in the API documentation so you know whether to add exception-handling code. More specifically, use the API documentation to figure out these things: Can the method/constructor call possibly throw an exception? On the API documentation page for the method/constructor, look for a throws section. If there's a throws section, that means the method/constructor can possibly throw an exception. If the method/constructor call throws an exception, is it checked or unchecked? On the API documentation page for the method/constructor, drill down on the exception class's name. On the API documentation page for the exception class, look at the exception class's class hierarchy. If you find RuntimeException is an ancestor of the exception, then the exception is an unchecked exception. Otherwise, it's a checked exception.

    23. 23 Using API Documentation when Writing Exception-Handling Code If the method/constructor call can possibly throw a checked exception, you must add a try-catch structure to handle it. If the method/constructor call can possibly throw an unchecked exception, you should read the API documentation to figure out the nature of the exception. And then, depending on the situation, 1) use a try-catch structure or 2) use careful code so that the exception won't be thrown. 1. Return to the first CreateNewFile code slide.1. Return to the first CreateNewFile code slide.

    24. 24 When a try Block Throws Different Types of Exceptions If several statements within a try block can possibly throw an exception and the exceptions are of different types, you should: Provide a generic catch block that handles every type of exception that might be thrown. or Provide a sequence of specific catch blocks, one for each type of exception that might be thrown. 1. We'll cover both of these techniques in detail in the upcoming slides. First, the generic catch block technique….1. We'll cover both of these techniques in detail in the upcoming slides. First, the generic catch block technique….

    25. 25 How to provide a generic catch block: Define a catch block with an Exception parameter. Inside the catch block, call the Exception class's getMessage method. For example: catch (Exception e) { System.out.println(e.getMessage()); } Why do all thrown exceptions match up with an Exception parameter? A thrown exception will be caught by a catch block if the thrown exception equals the catch heading's parameter or the thrown exception is a subclass of the catch heading's parameter. Since every thrown exception is a subclass of the Exception class, all thrown exceptions will match up with a generic Exception parameter. The Exception Class and its getMessage Method 1. I'll show a complete-program example shortly; this code fragment comes from that program. 2. I go back to the exception class hierarchy slide and show the Exception class above the other exception classes. [3. System-error classes are derived from the Error class, not the Exception class, but there's no need to worry about system-error classes.]1. I'll show a complete-program example shortly; this code fragment comes from that program. 2. I go back to the exception class hierarchy slide and show the Exception class above the other exception classes. [3. System-error classes are derived from the Error class, not the Exception class, but there's no need to worry about system-error classes.]

    26. 26 The Exception class's getMessage method returns a description of the thrown exception. For example, if you attempt to open a file using the FileReader constructor call and you pass in a file name for a file that doesn't exist, the getMessage call returns this: <filename> (The system cannot find the file specified) The Exception Class and its getMessage Method 1. The message displays the specified file name where it says <filename>. This message is pretty good, but be aware that sometimes getMessage returns messages that are pretty unhelpful.1. The message displays the specified file name where it says <filename>. This message is pretty good, but be aware that sometimes getMessage returns messages that are pretty unhelpful.

    27. 27 The program on the next slide opens a user-specified file and prints the file's first character. The FileReader constructor is in charge of opening the file. In your constructor call, if you pass in a file name for a file that doesn't exist, the JVM throws a FileNotFoundException. The read method is in charge of reading a single character from the opened file. If the file is corrupted and unreadable, the JVM throws an IOException. Note the generic catch block. It handles the different types of exceptions that might be thrown from within the try block. The Exception Class and its getMessage Method 1. As you know, file I/O is covered in the next chapter, Chapter 16. You're not responsible for the file details in this example, just the exception-handling details. 2. I walk through the entire program on the next 2 slides and return here. 3. I demo the PrintCharFromFile.java program by entering PrintCharFromFile.java (depending on the PC's configuration, I might have to use a full path). That generates this output: First char: / 4. I demo the program again, but this time with an invalid filename. 5. I've shown you an example of the FileReader constructor throwing an exception, but I haven't shown you an example of the read method throwing an exception. That's because it's harder to produce an exception with the read method call. It only occurs if you have a corrupted file that can be opened, but not read, and I can't generate such a file. Even though the read method call only rarely throws an exception, it's required that you have a try-catch mechanism for it because it has the potential of throwing the IOException exception and the IOException exception is a checked exception. [6. Chapter 15 explains how to use the Scanner class instead of the BufferedReader class for input from a text file. The Scanner class is more flexible and easier to use than the BufferedReader class. The BufferedReader class is more efficient when there’s a need to retrieve characters one at a time, and that’s what we’re doing in this program. Retrieving characters one at a time would be useful for programs that handle hypertext transfer protocol (HTTP) communications on the Internet because HTTP transmits data in the form of characters.] [7. Note: The point of this example is to illustrate having multiple catch blocks, and if Scanner were used instead of BufferedReader, then there would be no need for multiple catch blocks because Scanner’s methods don’t throw an IOException.]1. As you know, file I/O is covered in the next chapter, Chapter 16. You're not responsible for the file details in this example, just the exception-handling details. 2. I walk through the entire program on the next 2 slides and return here. 3. I demo the PrintCharFromFile.java program by entering PrintCharFromFile.java (depending on the PC's configuration, I might have to use a full path). That generates this output: First char: / 4. I demo the program again, but this time with an invalid filename. 5. I've shown you an example of the FileReader constructor throwing an exception, but I haven't shown you an example of the read method throwing an exception. That's because it's harder to produce an exception with the read method call. It only occurs if you have a corrupted file that can be opened, but not read, and I can't generate such a file. Even though the read method call only rarely throws an exception, it's required that you have a try-catch mechanism for it because it has the potential of throwing the IOException exception and the IOException exception is a checked exception. [6. Chapter 15 explains how to use the Scanner class instead of the BufferedReader class for input from a text file. The Scanner class is more flexible and easier to use than the BufferedReader class. The BufferedReader class is more efficient when there’s a need to retrieve characters one at a time, and that’s what we’re doing in this program. Retrieving characters one at a time would be useful for programs that handle hypertext transfer protocol (HTTP) communications on the Internet because HTTP transmits data in the form of characters.] [7. Note: The point of this example is to illustrate having multiple catch blocks, and if Scanner were used instead of BufferedReader, then there would be no need for multiple catch blocks because Scanner’s methods don’t throw an IOException.]

    28. 28 /*********************************************************** * PrintCharFromFile.java * Dean & Dean * * Open an existing text file and print a character from it. ***********************************************************/ import java.util.Scanner; import java.io.BufferedReader; import java.io.FileReader; public class PrintCharFromFile { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); String fileName; // name of target file BufferedReader fileIn; // target file char ch; // first character from fileIn The Exception Class and its getMessage Method

    29. 29 System.out.print("Enter a filename: "); fileName = stdIn.nextLine(); try { fileIn = new BufferedReader(new FileReader(fileName)); ch = (char) fileIn.read(); System.out.println("First character: " + ch); } // end try catch (Exception e) { System.out.println(e.getMessage()); } } // end main } // end PrintCharFromFile class The Exception Class and its getMessage Method 1. The read method returns the next character in the file. What is the purpose of the char cast operator? The read method’s return type is int, so to satisfy the compiler, the (char) cast is necessary. Why is the return type int? So read can return a special sentinel value, -1, when the end of the file has been reached . Thus, you can use a loop to read in all the characters in a file and terminate the loop when read returns -1. If the end of the file has not been reached, read returns a 16-bit char value with 16 extra 0 bits inserted at the left of the char value. The (char) cast operator removes the 16 extraneous 0 bits at the left.1. The read method returns the next character in the file. What is the purpose of the char cast operator? The read method’s return type is int, so to satisfy the compiler, the (char) cast is necessary. Why is the return type int? So read can return a special sentinel value, -1, when the end of the file has been reached . Thus, you can use a loop to read in all the characters in a file and terminate the loop when read returns -1. If the end of the file has not been reached, read returns a 16-bit char value with 16 extra 0 bits inserted at the left of the char value. The (char) cast operator removes the 16 extraneous 0 bits at the left.

    30. 30 Multiple catch Blocks If several statements within a try block can possibly throw an exception and the exceptions are of different types, and you don't want to use a generic catch block, you should: Provide a sequence of specific catch blocks, one for each type of exception that might be thrown. For example: catch (FileNotFoundException e) { System.out.println("Invalid filename: " + fileName); } catch (IOException e) { System.out.println("Error reading from file: " + fileName); } What's a benefit of using specific catch blocks rather than a generic catch block? 1. There are two ways to handle a try block that contains more than one dangerous statement. Use a generic catch block or use a sequence of catch blocks…. 2. These catch blocks come from the program on the next slide. It's a modified version of the PrintCharFromFile program. I walk through the program on the next slide and return here. 3. I demo the PrintCharFromFile2.java program: I enter a valid filename. I enter an invalid filename and note the error message. It's more user friendly than the message provided by getMessage. 4. You can provide more specific, more user-friendly error messages.1. There are two ways to handle a try block that contains more than one dangerous statement. Use a generic catch block or use a sequence of catch blocks…. 2. These catch blocks come from the program on the next slide. It's a modified version of the PrintCharFromFile program. I walk through the program on the next slide and return here. 3. I demo the PrintCharFromFile2.java program: I enter a valid filename. I enter an invalid filename and note the error message. It's more user friendly than the message provided by getMessage. 4. You can provide more specific, more user-friendly error messages.

    31. 31 import java.util.Scanner; import java.io.BufferedReader; import java.io.FileReader; import java.io.FileNotFoundException; import java.io.IOException; public class PrintCharFromFile2 { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); String fileName; // name of target file BufferedReader fileIn; // target file char ch; // first character from fileIn System.out.print("Enter a filename: "); fileName = stdIn.nextLine(); The Exception Class and its getMessage Method

    32. 32 try { fileIn = new BufferedReader(new FileReader(fileName)); ch = (char) fileIn.read(); System.out.println("First character: " + ch); } // end try catch (FileNotFoundException e) { System.out.println("Invalid filename: " + fileName); } catch (IOException e) { System.out.println("Error reading from file: " + fileName); } } // end main } // end PrintCharFromFile2 class The Exception Class and its getMessage Method

    33. 33 Multiple catch Blocks If multiple catch blocks are used, the first catch block that matches the type of the exception thrown is the one that is executed; the other catch blocks are then skipped. 1. This behavior is similar to the behavior of what other Java construct? The switch statement! But with a switch statement, after a matching case block is found and executed, control continues to the next case unless there happens to be a break statement. With catch blocks, after a catch block is executed, the subsequent catch blocks are automatically skipped. 2. So in the previous slide's program, if a FileNotFoundException is thrown, the first catch block is executed and then the JVM skips the second catch block without bothering to see if the second catch block matches up with the thrown exception.1. This behavior is similar to the behavior of what other Java construct? The switch statement! But with a switch statement, after a matching case block is found and executed, control continues to the next case unless there happens to be a break statement. With catch blocks, after a catch block is executed, the subsequent catch blocks are automatically skipped. 2. So in the previous slide's program, if a FileNotFoundException is thrown, the first catch block is executed and then the JVM skips the second catch block without bothering to see if the second catch block matches up with the thrown exception.

    34. 34 Understanding Exception Messages As you know, if your code involves a checked exception being thrown, you must include a try/catch for that code. Without the try/catch, your program won't compile successfully. On the other hand, if your code involves an unchecked exception being thrown, it's optional whether you include a try/catch for that code. Without the try/catch, your program will compile successfully, but if an exception is thrown, your program will crash. If such a crash occurs, the JVM prints a runtime error message that describes the thrown exception. 1. Unless you're an unbelievably good programmer, you've probably seen runtime error messages in the past, but prior to this chapter, you weren't properly prepared to thoroughly understand them. Now you are….1. Unless you're an unbelievably good programmer, you've probably seen runtime error messages in the past, but prior to this chapter, you weren't properly prepared to thoroughly understand them. Now you are….

    35. 35 Understanding Exception Messages import java.util.Scanner; public class NumberList { private int[] numList = new int[100]; // array of numbers private int size = 0; // number of numbers //*************************************** public void readNumbers() { Scanner stdIn = new Scanner(System.in); String xStr; // user-entered number (String form) int x; // user-entered number System.out.print("Enter a whole number (q to quit): "); xStr = stdIn.next(); while (!xStr.equalsIgnoreCase("q")) { x = Integer.parseInt(xStr); numList[size] = x; size++; System.out.print("Enter a whole number (q to quit): "); 1. This program reads in a list of numbers and calculates the mean. I walk through the program on this and the next slide, starting with main. 2. The program compiles and runs successfully most of the time, but it's not very robust. Under what circumstances will the program crash? After I get students' answers, I go to the slide after the program.1. This program reads in a list of numbers and calculates the mean. I walk through the program on this and the next slide, starting with main. 2. The program compiles and runs successfully most of the time, but it's not very robust. Under what circumstances will the program crash? After I get students' answers, I go to the slide after the program.

    36. 36 Understanding Exception Messages xStr = stdIn.next(); } // end while } // end readNumbers //*************************************** public double getMean() { int sum = 0; for (int i=0; i<size; i++) { sum += numList[i]; } return sum / size; } // end getMean //*************************************** public static void main(String[] args) { NumberList list = new NumberList(); list.readNumbers(); System.out.println("Mean = " + list.getMean()); } // end main } // end class NumberList

    37. 37 Understanding Exception Messages The NumberList program compiles and runs, but it's not very robust. See below: 1. I go to the program and show the parseInt call. If the user enters hi, the parseInt call causes a NumberFormatException object to be thrown. Since there's no try/catch, the program prints the error message shown here and terminates. 2. Let's analyze the error message. The JVM prints the exception that was thrown (NumberFormatException) and then it prints the call stack trace - the methods that were called prior to the crash. What methods were called? parseInt, readNumbers, main I go to the next slide and show that I've more formally presented this material there. I read the first bullet item there and then return here. 3. I go to the program and show the size declaration's initialization to 0, the readNumbers method's loop heading, and the getMean method's divide-by-size operation. If you divide an integer by 0, what type of exception is thrown? The error message shows that an ArithmeticException object is thown. I go to the next slide, read the second bullet item there and its associated hidden note, and then return here. 4. I go to the program and show the readNumbers method's numList[i] assignment. If you use an array index that's < 0 or >= the array's size, what type of exception is thrown? The error message shows that an ArrayIndexOutOfBoundsException object is thown. I go to the next slide and read the third bullet item there.1. I go to the program and show the parseInt call. If the user enters hi, the parseInt call causes a NumberFormatException object to be thrown. Since there's no try/catch, the program prints the error message shown here and terminates. 2. Let's analyze the error message. The JVM prints the exception that was thrown (NumberFormatException) and then it prints the call stack trace - the methods that were called prior to the crash. What methods were called? parseInt, readNumbers, main I go to the next slide and show that I've more formally presented this material there. I read the first bullet item there and then return here. 3. I go to the program and show the size declaration's initialization to 0, the readNumbers method's loop heading, and the getMean method's divide-by-size operation. If you divide an integer by 0, what type of exception is thrown? The error message shows that an ArithmeticException object is thown. I go to the next slide, read the second bullet item there and its associated hidden note, and then return here. 4. I go to the program and show the readNumbers method's numList[i] assignment. If you use an array index that's < 0 or >= the array's size, what type of exception is thrown? The error message shows that an ArrayIndexOutOfBoundsException object is thown. I go to the next slide and read the third bullet item there.

    38. 38 Understanding Exception Messages As part of a runtime error, the JVM prints the exception that was thrown and then prints the call-stack trace. The call-stack trace shows the methods that were called prior to the crash. If you perform integer division with a denominator of zero, the JVM throws an ArithmeticException object. If you access an array element with an array index that's < 0 or >= the array's size, the JVM throws an ArrayIndexOutOfBoundsException object. 1. Note that if you perform floating-point division with a denominator of zero, the JVM allows it. If the numerator is a positive number, the division operation returns the value Infinity. If the numerator is a negative number, the division operation returns the value -Infinity. If the numerator is a zero, the division operation returns the value NaN (for not a number). 2. The point of all this is to be able to understand runtime error messages. Normally, when you see a runtime error message, you should try to fix your code so as to avoid the runtime error message in the future. Since the fixes are pretty straightforward for the three errors in the NumberList program, I won't bother to cover them in lecture. One of the exercises in the book asks you to implement the fixes.1. Note that if you perform floating-point division with a denominator of zero, the JVM allows it. If the numerator is a positive number, the division operation returns the value Infinity. If the numerator is a negative number, the division operation returns the value -Infinity. If the numerator is a zero, the division operation returns the value NaN (for not a number). 2. The point of all this is to be able to understand runtime error messages. Normally, when you see a runtime error message, you should try to fix your code so as to avoid the runtime error message in the future. Since the fixes are pretty straightforward for the three errors in the NumberList program, I won't bother to cover them in lecture. One of the exercises in the book asks you to implement the fixes.

    39. 39 Chapter 14 - Quiz Questions If you call the parseInt method and pass in "45.2%" as the argument, what type of exception would be thrown? InvalidNumberException NumberFormatException ParseError 1. c 2. b1. c 2. b

    40. 40 Chapter 14 - Quiz Questions 3. a3. a

More Related