LinesReaderAndPrinterPropagatingExceptions.java |
package lectures.exceptions; import util.annotations.WebDocuments; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * COOPERATIVE EXECEPTION PROCESSING * We finally see cooperative exception processing, exceptions thrown in called * methods being handled by calling methods. * * Look first at echoLines and numberOfInputLines, then at main. * * */ @WebDocuments({"Lectures/Exceptions.pptx", "Lectures/Exceptions.pdf", "Videos/Exceptions.avi"}) public class LinesReaderAndPrinterPropagatingExceptions { static BufferedReader input = new BufferedReader(new InputStreamReader( System.in)); /** * This method no longer has code to "catch" the IOException that can * result from readLine as it does not have enough context to handle the exception. * To document this, it has a header with the throws clause, to warn its caller about this. * * (The throws clause is usually on the same line as the rest of the header, it is * just on a different line here to make it easier to comment out later) */ static void echoLines(int numberOfInputLines) /* * Comment out the throws class when instructed */ throws IOException { for (int inputNum = 0; inputNum < numberOfInputLines; inputNum++) { System.out.println(input.readLine()); } } /** * This method too no longer has code to "catch" the exception and documents this fact * for its caller. */ static int numberOfInputLines(String[] args) /* * Comment out the throws class when instructed */ throws ArrayIndexOutOfBoundsException { /* * Put breakpoint on the next line. * */ return Integer.parseInt(args[0]); } /** * This main now handles exceptions not caught in the two methods it calls. */ public static void main(String args[]) /* * Uncomment the throws clause when instructed. */ // throws IOException, ArrayIndexOutOfBoundsException { try { echoLines(numberOfInputLines(args)); // if this echoLines fails where will the program go next? } /* * Comment out this catch when instructed */ catch (ArrayIndexOutOfBoundsException e) { System.out .println("Did not enter an argument. Assuming a single input line."); // Why is this try in a catch? try { echoLines(1); // if this echoLines fails where will the program go next? } catch (IOException ioe) { System.out .println("Did not input the one input string, which is the default" + " in case of missing argument, before input was closed. "); } } /* * Comment out this catch when instructed */ catch (IOException e) { System.out .println("Did not input the correct number of input strings before input was closed. "); } } } /* * * Put breakpoint in numberOfInputLine and debug-run the code without * entering a main argument. Press F6 (step over) to follow the control flow * when the statement is executed. * * (T/F) LinesReaderAndPrinterPropagatingExceptions with no argument executes * (one or more statements in) a try block of numberOfInputLines. * * (T/F) LinesReaderAndPrinterPropagatingExceptions with no argument executes * (one or more statements in) a catch block of numberOfInputLines. * * (T/F) LinesReaderAndPrinterPropagatingExceptions with no argument executes * (one or more statements in) a try block of main. * * (T/F) LinesReaderAndPrinterPropagatingExceptions with no argument executes * (one or more statements in) a catch block of main. * * (T/F) If method p calls method q, and the execution of q results in an exception * of type E not handled by a catch block of q, then control transfers to a * catch block of p that can handle an exception of type E. * * (T/F) LinesReaderAndPrinterPropagatingExceptions with no argument executes * (one or more statements in) a try block of echoLines. * * (T/F) LinesReaderAndPrinterPropagatingExceptions with no argument reads input * from user. * * (T/F) A catch block can recover from an exception thrown by executing some * error-prone method by nesting it in a try block. * * Comment out throws clause in the header of echoLines. * * What happens? * * (T/F) If a method p executes a statement that can throw an IOException, * then p must either catch the exception or acknowledge in the header * that it is not catching the exception. * * Uncomment the throws clause in the header of echoLines. * * Comment out the throws clause in the header of numberOfInputLines. * * What happens? * * (T/F) If a method p executes a statement that can throw an ArrayIndexOutOfBoundsException, * then p must either catch the exception or acknowledge in the header * that it is not catching the exception. * * Uncomment the throws clause in the header of numberOfInputLines. * * Java has two kinds of exceptions, checked and unchecked. * * If a method p executes a statement that can throw a checked exception * then p must either catch the exception or acknowledge in the header * that it is not catching the exception. * * Unchecked exceptions do not have to be acknowledged in headers or caught in * catch blocks. * * (T/F) IOException is a checked exception. * * (T/F) ArrayIndexOutOfBoundsException is a checked exception. * * Comment out the IOException catch block in main. * What happens? * * Uncomment the throws clause in the header of main. * What happens? * * (T/F) If a method p can execute a statement that directly or indirectly can throw * an IOException that is catchable in p, then p must either catch the exception or * acknowledge in the header that it is not catching the exception and thus propagating * or throwing the exception to its caller. * * * Uncomment the IOException catch block in main. * * So now both the throws clause and the corresponding catch block are in the * program. * * (T/F) It is possible for an IOException to be both caught by main and * propagated to its caller. * * Hint: You can answer this question based on what Java allows, or you could try adding * "throw e;" at the end of the IOException catch block. * * (T/F) Java allows checked exceptions to be acknowledged in method headers even * if they are not propagated to callers. * * The Halting problem says that it is not possible for Java to always know if some * statement will actually be executed at runtime. * * (T/F) The halting problem prevents Java from always knowing if an exception will actually * be thrown by a try block. * * As we have seen, at compile time we do not know which implementation of a * method will actually be invoked to service a method call. If the call is an external call * targeted at a variable typed using an interface, then answer depends on the class of * the object assigned to the variable. If the call is made in class C to an * internal (inherited or declared) method m of C, then the method actually invoked * may be an overriding method m in some subclass of C. In both cases, the method * call is dynamically dispatched at runtime. This means the header of a method * in an interface or class must advertise the union of all exceptions * thrown by implementing and overriding methods respectively. * * (T/F) Dynamic dispatching prevents Java from always knowing which exceptions will be * thrown by a method call. * * (T/F) When in doubt, is it better to be conservative and over advertise the thrown * checked exceptions in a method header so that the a caller can always handle an exception * that propagates to it. * * * Two questions that arise are: * * How do programmers tell Java which exceptions are checked and which are not? * Why two kinds of exceptions? * * * An unchecked exception has {@link RuntimeException} as a superclass, a checked * exception does not. Hover over the name to see the full description. * * Now the more interesting question: Why two kinds of exceptions? * Would you revolt if all exceptions were checked, regardless of context? * If so, why? * * Hint: There certain kinds of exceptions that can never be avoided no matter * how well you program because of external forces such as users and other remote programs. * Certain kinds of exceptions can be avoided, at least in some cases. * * In this example, the ArrayIndexOutOfBoundsException is a result of user * error but it can be avoided in other contexts. * * Problem 1: Given the above, how does the programmer of numberOfInputLines (who * does not want to handle the exception because of lack of context) inform its callers about * this uncaught exception so one or more of them can handle it? * * Problem 2: How does the programmer also force some caller in the stack of * calls to handle the lack of a user argument (since the current exception is * unchecked)? * * Problem 3: The exception ArrayIndexOutBoundsException can be as unindicative of the cause * of the exception - missing argument - to the caller as the error message about * array index out of bounds was to the end user. * * Go to LinesReaderAndPrinterUsingProgrammerDefinedException * * * */