1 / 45

Chapter 15 - Exception Handling

Chapter 15 - 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

Télécharger la présentation

Chapter 15 - 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. Chapter 15 - Exception Handling 1 • 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 • Generic catch Block With Exception Class • Multiple catch Blocks and Multiple Exceptions Per Block • Understanding Exception Messages • Using throws to Postpone the catch • Automatic Cleanup with Try-With-Resources

  2. Using try and catch Blocks to Handle "Dangerous" Method Calls 2 • 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.

  3. Using try and catch Blocks to Handle "Dangerous" Method Calls 3 • 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."); } Normally, one or more of these statements will be a "dangerous" API method call or constructor call. The exception class should match the type of exception that the try block might throw.

  4. Using try and catch Blocks to Handle "Dangerous" Method Calls 4 • Semantics for previous slide's try and catch code fragment: • If the userEntry string contains all digits, then: • The int version of userEntry is assigned into quantity. • 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; that is, 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.

  5. NumberFormatException 5 • 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");

  6. Line Plot Example 6 • 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

  7. Line Plot Example 7 //************************************************************* 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 reads a group of characters and stops at whitespace

  8. try and catch Blocks - More Details 9 • 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.

  9. try and catch Blocks - More Details 10 • 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.

  10. try and catch Blocks - More Details 11 • 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 statements inside a try block might possibly be skipped, and it assumes the worst. 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.

  11. try and catch Blocks - More Details 12 • 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 compilation error: variable valid might not have been initialized compilation error: variable x might not have been initialized

  12. Two Types of Exceptions - Checked and Unchecked 13 • 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.

  13. Two Types of Exceptions - Checked and Unchecked 14 The parseInt, parseLong, parseDouble, etc. methods all throw a NumberFormatException object.

  14. Unchecked Exceptions 15 • 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 prior GetIntFromUser example). 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).

  15. Unchecked Exceptions 16 • 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.

  16. Unchecked Exceptions 17 • 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

  17. Unchecked Exceptions 18 • 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

  18. Checked Exceptions 19 • 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?

  19. Checked Exceptions 20 /************************************************************* * CreateTimestampFile.java * Dean & Dean * * This program creates a file, using a timestamp for its name. *************************************************************/ import java.util.Date; import java.nio.file.*; // for Path, Paths, Files public class CreateTimestampFile { public static void main(String[] args) { String timestamp; // current date and time String filename; // use timestamp for this filename Path path; // file location timestamp = new Date().toString(); filename = timestamp.replaceAll(" ", "_").replaceAll(":", "_") + ".txt"; path = Paths.get(filename); Files.createFile(path); System.out.println(filename + " created."); } // end main } // end CreateTimestampFile class unknown API constructor call unknown API method calls

  20. Using API Documentation when Writing Exception-Handling Code 21 • 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.

  21. Using API Documentation when Writing Exception-Handling Code 22 • If the method/constructor call can possibly throw a checked exception, you must add a try-catch mechanism 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 mechanism or 2) use careful code so that the exception won't be thrown.

  22. Using API Documentation when Writing Exception-Handling Code 23 • Handling the three "unknown" API method calls in the CreateTimestampFile Program: • new Date() • Instantiates a Date object that holds the current time. • No exceptions are thrown. • Paths.get(filename) • Returns a Java Path object, which defines a file and its directory path. • Throws an unchecked InvalidPathException if its filename argument contains characters that are illegal in a filename and path. • Files.createFile(path) • Creates a file stored in auxiliary memory. • Throws a checked IOException if there's an I/O problem, like a corrupt hard disk. • Throws a checked FileAlreadyExistsException if there's an attempt to create a file that already exists. • Throws 2 unchecked exceptions - UnsupportedOperationException and SecurityException, which can be ignored for this program.

  23. Improved CreateTimestampFile Program 24 import java.util.Date; import java.io.IOException; import java.nio.file.*; // for Path, Paths, Files public class CreateTimestampFile { public static void main(String[] args) { String timestamp; // current date and time String filename; // use timestamp for this filename Path path; // file location timestamp = new Date().toString(); filename = timestamp.replaceAll(" ", "_").replaceAll(":", "_") + ".txt"; path = Paths.get(filename); try { Files.createFile(path); System.out.println(filename + " created."); } catch (IOException e) { System.out.println("File I/O error"); } } // end main } // end CreateTimestampFile class We need a try block for the 2 checked exceptions - IOException and FileAlreadyExistsException. Since IOException is a superclass of FileAlreadyExistsException, we can use the single IOException parameter to catch both types of thrown exceptions.

  24. When a try Block Throws Different Types of Exceptions 25 • 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, with each catch block handling a different exception type or group of exception types.

  25. Generic catch Block with Exception Class 26 • How to provide a generic catch block: • Define a catch block with an Exception parameter, e. • Optionally, inside the catch block, use the e exception object to call: • getClass().getName(), which returns the class name of the thrown exception object. • getMessage(), which returns a description of the thrown exception. • For example: catch (Exception e) { System.out.println(e.getClass().getName()); System.out.println(e.getMessage()); }

  26. Generic catch Block with Exception Class 27 • In a catch block heading, if you use an Exception parameter, then all thrown exceptions will match up with the Exception parameter. Why? • A thrown exception will be caught by a catch block if the thrown exception's class equals the catch heading's parameter's class or the thrown exception's class is a subclass of the catch heading's parameter's class. • Since every thrown exception's class is a subclass of the Exception class, all thrown exceptions will match up with a generic Exception parameter. • The ReadFromFile program (on the next slide) illustrates how to use a generic catch block to handle multiple types of thrown exceptions. • The program opens a user-specified file and prints all the lines in that file.

  27. Generic catch Block with Exception Class 28 /*********************************************************** * ReadFromFile.java * Dean & Dean * * This opens an existing text file and prints its lines. ***********************************************************/ import java.util.Scanner; import java.nio.file.Paths; public class ReadFromFile { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); Scanner fileIn; // file handler String filename; // user-specified file name String line; // line of text

  28. Generic catch Block with Exception Class 29 System.out.print("Enter a filename: "); try { filename = stdIn.nextLine(); fileIn = new Scanner(Paths.get(filename)); while (fileIn.hasNext()) { line = fileIn.nextLine(); System.out.println(line); } } // end try catch (Exception e) { System.out.println( "Thrown exception: " + e.getClass().getName()); System.out.println( "Exception message: " + e.getMessage()); } } // end main } // end ReadFromFile class This Scanner constructor throws a checked exception.

  29. Generic catch Block with Exception Class 30 • Sample session #1: Enter a filename: Einstein.* Thrown exception: java.nio.file.InvalidPathException Exception message: Illegal char <*> at index 9: Einstein.* • Sample session #2: Enter a filename: Einstein Thrown exception: java.nio.file.NoSuchFileException Exception message: Einstein • Sample session #3: Enter a filename: Einstein.txt A scientific theory should be as simple as possible, but not simpler.

  30. Generic catch Block with Exception Class 31 • The ReadFromFile program contains quite a few operations that can potentially throw an exception: • Paths.get throws an InvalidPathException (an unchecked exception). • The Scanner constructor throws an IOException(a checked exception). • hasNext throws IllegalStateException(an unchecked exception). • nextLine throwsIllegalStateException and NoSuchElementException (both unchecked exceptions). • The program handles all of the exceptions above (checked and unchecked) with a generic catch block and its getClass().getName()and getMessage() method calls.

  31. Multiple catch Blocks and Multiple Exceptions Per Block 32 • When a try block might throw more than one type of exception, instead of providing one generic catch block, you can provide a sequence of catch blocks, with each catch block handling a different exception type or group of exception types. • For example: catch (InvalidPathException | NoSuchFileException e) { System.out.println("Filename invalid or not found."); } // end catching exceptions user can handle catch (Exception e) { System.out.println(e.getClass() + ":"); System.out.println(e.getMessage()); } • What is a benefit of using multiple catch blocks rather than a single generic catch block?

  32. Multiple catch Blocks and Multiple Exceptions Per Block 33 /************************************************************* * ReadFromFile2.java * Dean & Dean * * This opens an existing text file and prints its lines. *************************************************************/ import java.util.Scanner; import java.nio.file.*; // Paths, specific exceptions public class ReadFromFile2 { public static void main(String[] args) { Scanner stdIn = new Scanner(System.in); Scanner fileIn; // file handler boolean validUserEntry = false; do { System.out.print("Enter a filename: ");

  33. Multiple catch Blocks and Multiple Exceptions Per Block 34 try { fileIn = new Scanner(Paths.get(stdIn.nextLine())); // Above statement succeeds only when valid user input validUserEntry = true; while (fileIn.hasNext()) { System.out.println(fileIn.nextLine()); } } // end try catch (InvalidPathException | NoSuchFileException e) { System.out.println("Filename invalid or not found."); } // end catching exceptions user can handle catch (Exception e) { System.out.println(e.getClass() + ":"); System.out.println(e.getMessage()); } } while (!validUserEntry); } // end main } // end ReadFromFile2 class Rules for multiple exceptions in a catch block heading: Use a single vertical bar to separate the parameters. The exception parameters must not be in the same class hierarchy tree.

  34. Multiple catch Block Execution Sequence 35 • 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. • Whenever you use more than one catch block after a given try block, and one catch block's exception class is derived from another catch block's exception class, to avoid a compilation error, you must arrange the catch blocks with the more general exception classes at the bottom (the superclasses go at the bottom). • For example, in the prior ReadFromFile2 program, you must put the Exceptioncatch block at the bottom because the Exception class is a superclass of the InvalidPathException and NoSuchFileException classes.

  35. Multiple catch Block Development 36 • The original ReadFromFile program shows how you can use the compiler’s knowledge and experiment with a simple generic catch block to discover the types of exceptions that might be thrown by various forms of bad input. • Once you have discovered all the types of exceptions that bad user entries might generate, you can put these particular exceptions into additional catch block(s) inserted before the generic catch block. • Then, modify the code so that if a bad entry occurs, the program prints a short error message, repeats the original prompt, and prompts for new input.

  36. Understanding Exception Messages 37 • As you know, if your code involves a checked exception being thrown, you must include a try-catch mechanism for that code. Without the try-catch mechanism, 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 mechanism for that code. Without it, 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.

  37. Understanding Exception Messages 38 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): ");

  38. Understanding Exception Messages 39 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

  39. Understanding Exception Messages 40 • The NumberList program compiles and runs, but it's not very robust. See below: thrown exception call-stack trace

  40. Understanding Exception Messages 41 • 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.

  41. Using throws to Postpone the catch 42 • Suppose you have a utility method that might throw an exception, but the original causes of that exception are in the calling methods. • Or suppose you have a non-void return method that sometimes throws an exception and that method’s exception handler cannot know what value to have the method return. • Then it’s appropriate to move the try and catch blocks from the called method back to the calling method(s). To do this, append throws <exception-type> to the called method’s header. • For example, suppose you want a variation of the previous removeStudent method to return the removed student’s name: public String removeStudent(int index) throws IndexOutOfBoundsException { return students.remove(index); } // end removeStudent

  42. Using throws to Postpone the catch 43 Scanner stdIn = new Scanner(System.in); String[] names = {"Caleb", "Izumi", "Mary", "Usha"}; StudentList2 studentList = new StudentList2(names); int index; boolean reenter; do { System.out.print("Enter index of student to remove: "); index = stdIn.nextInt(); try { System.out.println( "removed " + studentList.removeStudent(index)); reenter = false; } catch (IndexOutOfBoundsException e) { System.out.print("Invalid entry. "); reenter = true; } } while (reenter);

  43. Cleanup With finally Block 44 • Sometimes you need to provide cleanup code that executes regardless of whether an exception is thrown. For example, after writing to a file, you must close the file to complete the writing process. Closing also releases system resources and improves system performance. • Unfortunately, if some operation between file opening and file closing throws an exception, the close operation might be skipped. • The traditional way to deal with this is to put an explicit close method call in a separate finally block located immediately after the last catch block, like this: finally { if (fileOut != null) { fileOut.close(); } } // end finally • That’s ugly. Starting with Java 1.7, there’s a better way.

  44. Automatic Cleanup Using Try-With-Resources 45 • All classes that implement Closeable also implement AutoCloseable. When an object is AutoCloseable, instead of closing it with an explicit close statement, we can ask the JVM to close it for us by opening the AutoCloseable object with a try-with-resources header, like this: /************************************************************* * WriteToFile.java * Dean & Dean * * This demonstrates a file writer using try-with-resources *************************************************************/ import java.io.*; // PrintWriter, IOException public class WriteToFile { public int write(String filename, String text) throws IOException { try (PrintWriter fileOut = new PrintWriter(filename)) { fileOut.println(text); return text.length(); // if exception is not thrown } // end try and close fileOut automatically } // end write

  45. Automatic Cleanup Using Try-With-Resources 46 public static void main(String[] args) { String filename = "Feynman.txt"; String text = "It is fundamentally impossible to make " + "a precise prediction\n of exactly what will happen " + "in a given experiment."; int length = 0; WriteToFile writer = new WriteToFile(); try { length = writer.write(filename, text); System.out.println("written string length = " + length); } catch (Exception e) { System.out.println(e.getClass()); System.out.println(e.getMessage()); } } // end main } // end class WriteToFile Sample session: written string length = 111

More Related