Chapter 12 handling errors through exceptions
The basic idea of java is that "poorly structured code cannot run“
In this way, you can be more confident that there are no unhandled errors in your application. Exception handling is the only formal error reporting mechanism in Java and is enforced by the compiler.
12.1 concept
Separate the code "describing what to do in the normal execution process" from the code "what to do if something goes wrong". The exception separates the code.
12.2 basic concepts
When an exception is thrown
- Use new to create an exception object on the heap
- The current execution path (he cannot continue) is terminated and a reference to the exception object is popped from the current environment
- Exception handling mechanism takeover procedure
- Find an appropriate place (exception handler) to continue executing the program
- Recover a program from an error state so that the program can either run another way or continue to run
12.2.1 abnormal parameters
Create an exception object on the heap with new, along with the allocation of storage space and the call of constructor. All standard exception classes have two constructors:
- One is the default constructor
- The other takes a string as a parameter so that relevant information can be put into the constructor of the exception object
Throw new NullPointerException("t = null");
After new creates the exception object, the reference of this object will be passed to throw. Although the type of the returned exception object is usually different from the return type designed by the method, in effect, it is like "returning" from the method.
12.3 catching exceptions
Concept of monitored region
12.3.1 try block
Exception thrown inside the method (exception thrown by calling other methods inside the method)
12.3.1 exception handling procedure
Immediately after try, it is represented by the keyword catch (it looks like accepting one and only one special type of method)
-
When an exception is thrown, the exception handling mechanism will be responsible for searching for the first handler whose parameters match the exception type
-
Then enter the catch clause for execution. At this time, it is considered that the exception has been handled
-
The catch clause ends and the lookup process of the handler ends
-
Only matching catch can be executed
Termination and recovery
There are two basic models of exception handling in theory.
- Java supports the termination model (which is supported by Java and C + +). In this model, once an exception is thrown, it indicates that the error has been irreparable and cannot be returned to continue execution.
- Restore the model. The job of the exception handler is to fix the error, then try to call the problem method again and think it will succeed the second time. For the recovery model, you usually want to continue to execute the program after the exception is handled.
- If Java implements recovery like behavior, it can't throw an exception when encountering an error, but call a method to correct the error, or put try into a while loop, so it will continue to enter the try block until a satisfactory result is obtained.
- Restorative exceptions lead to coupling. Restorative programs need to know where exceptions are thrown, which must include non generic code that depends on where exceptions are thrown.
12.4 create custom exception
Define your own exception class to represent the specific problems that may be encountered in the program. It is best to choose the exception class with similar meaning to inherit.
Exercise 1
/* Create a class with a main(0 that throws an object of class Exception * inside a try block. Give the constructor for Exception a String argument. * Catch the exception inside a catch clause and print the String argument. * Add a finally clause and print a message to prove you were there. */ class Exception1 extends Exception { public Exception1(String msg) { super(msg);//super construct base class constructor System.out.println("Exception1(String msg)"); } } public class No1Ex { public static void f() throws Exception1 { System.out.println("Throwing MyException from f()"); throw new Exception1("From f()"); } public static void main(String[] args) { try { f(); } catch(Exception1 e) { System.err.println("Caught Exception1"); e.printStackTrace(); } finally { System.out.println("Made it to finally"); } } } ============================================================= Throwing MyException from f() Exception1(String msg) Made it to finally Caught Exception1 Chapter XII exception handling.Exception1: From f() at Chapter XII exception handling.No1Ex.f(No1Ex.java:18) at Chapter XII exception handling.No1Ex.main(No1Ex.java:22)
Exercise 2
/* Define an object reference and initialize it to null. Try to call a method * through this reference. Now wrap the code in a try-catch clause to catch the * exception. */ public class No2Ex { private static Integer i = null; public static void main(String[] args) { // leads to NullPointerException: // System.out.println(i.toString()); try { System.out.println(i.toString()); } catch(NullPointerException e) { System.err.println("Caught NullPointerException"); e.printStackTrace(); } try { i = 10; System.out.println(i.toString()); } catch(NullPointerException e) { System.err.println("Caught NullPointerException"); e.printStackTrace(); } finally { System.out.println("Got through it"); } } } ======================================================================= Caught NullPointerException java.lang.NullPointerException at Chapter XII exception handling.No2Ex.main(No2Ex.java:14) 10 Got through it
Exercise 3
package Chapter XII exception handling; // Write code to generate and catch an ArrayIndexOutOfBoundsException. public class No3Ex { private static int[] ia = new int[2]; public static void main(String[] args) { try { ia[2] = 3; } catch(ArrayIndexOutOfBoundsException e) { System.err.println( "Caught ArrayIndexOutOfBoundsException"); e.printStackTrace(); } } } ========================================================================= Caught ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException: 2 at Chapter XII exception handling.No3Ex.main(No3Ex.java:8)
Exercise 4
/* Create your own exception class using the extends keyword. Write a * constructor for this class that takes a String argument and stores it inside * the object with a String reference. Write a method that displays the stored * String. Create a try-catch clause to exercise your new exception. */ class Exception4 extends Exception { private String msg; Exception4(String msg) { super(msg); System.out.println("Exception4()"); this.msg = msg; } protected void showS() { System.out.println("Message from Exception4: " + msg); } } public class No4Ex { public static void f() throws Exception4 { System.out.println("f()"); throw new Exception4("Ouch from f()"); } public static void main(String[] args) { try { f(); } catch(Exception4 e) { System.err.println("Caught Exception4"); e.printStackTrace(); e.showS(); } } } =============================================================f() Exception4() Message from Exception4: Ouch from f() Caught Exception4 Chapter XII exception handling.Exception4: Ouch from f() at Chapter XII exception handling.No4Ex.f(No4Ex.java:24) at Chapter XII exception handling.No4Ex.main(No4Ex.java:28)
Exercise 5
/* Create you own resumption-like behavior using a while loop that repeats * until an exception is no longer thrown. */ public class No5Ex { private static int[] ia = new int[2]; static int x = 5; public static void main(String[] args) { while(true) { try { ia[x] = 1; System.out.println(ia[x]); break; } catch(ArrayIndexOutOfBoundsException e) { System.err.println( "Caught ArrayIndexOutOfBoundsException"); e.printStackTrace(); x--; } finally { System.out.println("Are we done yet?"); } } System.out.println("Now, we're done."); } } ======================================================================== Caught ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException: 5 at Chapter XII exception handling.No5Ex.main(No5Ex.java:13) Caught ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException: 4 at Chapter XII exception handling.No5Ex.main(No5Ex.java:13) Caught ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException: 3 at Chapter XII exception handling.No5Ex.main(No5Ex.java:13) Caught ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException: 2 at Chapter XII exception handling.No5Ex.main(No5Ex.java:13) Are we done yet? Are we done yet? Are we done yet? Are we done yet? 1 Are we done yet? Now, we're done.
12.4.1 exception and record log
Using Java util. The logging tool logs the output to a log.
LoggingException builds all the logging infrastructure in the exception itself, which makes it very convenient to use.
Exercise 6
/* Create two exception classes, each of which performs its own logging * automtically. Demonstrate that these work. */ import java.util.logging.*; import java.io.*; class Oops1 extends Exception { private static Logger logger = Logger.getLogger("LoggingException");//The name of the package or class associated with the error public Oops1() { StringWriter trace = new StringWriter(); printStackTrace(new PrintWriter(trace));//Get the stack track of the throwing place and accept Java. io. The PrintWriter object is used as a parameter to produce a string logger.severe(trace.toString());//Sever directly calls the methods associated with the log level } } class Oops2 extends Exception { private static Logger logger = Logger.getLogger("LoggingException"); public Oops2() { StringWriter trace = new StringWriter(); printStackTrace(new PrintWriter(trace)); logger.severe(trace.toString()); } } public class No6Ex { static void f() throws Oops1 { throw new Oops1(); } static void g() throws Oops2 { throw new Oops2(); } public static void main(String[] args) { try { f(); } catch(Exception Oops1) {} try { g(); } catch(Exception Oops2) {} } } ======================================================================= February 16, 2021 9:44:22 Chapter 12 exception handling.Oops1 <init> serious: Chapter XII exception handling.Oops1 at Chapter XII exception handling.No6Ex.f(No6Ex.java:29) at Chapter XII exception handling.No6Ex.main(No6Ex.java:36) February 16, 2021 9:44:22 Chapter 12 exception handling.Oops2 <init> serious: Chapter XII exception handling.Oops2 at Chapter XII exception handling.No6Ex.g(No6Ex.java:32) at Chapter XII exception handling.No6Ex.main(No6Ex.java:39)
Exercise 7
// Modify Exercise 3 so that the catch clause logs the result. import java.util.logging.*; import java.io.*; public class No7Ex { private static int[] ia = new int[2]; private static Logger logger = Logger.getLogger("Ex7 Exceptions"); static void logException(Exception e) { // Exception e argument StringWriter trace = new StringWriter(); e.printStackTrace(new PrintWriter(trace)); logger.severe(trace.toString()); } public static void main(String[] args) { try { ia[2] = 3; } catch(ArrayIndexOutOfBoundsException e) { System.err.println( "Caught ArrayIndexOutOfBoundsException"); e.printStackTrace(); // call logging method: logException(e); } } } ==================================================================== Caught ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException: 2 at Chapter XII exception handling.No7Ex.main(No7Ex.java:18) February 16, 2021 10:04:45 Chapter 12 exception handling.No7Ex logException serious: java.lang.ArrayIndexOutOfBoundsException: 2 at Chapter XII exception handling.No7Ex.main(No7Ex.java:18)
12.5 description of abnormality
Java encourages people to inform the client programmer using this method of the exceptions that may be thrown by the method, which enables the caller to know exactly what code to write to catch all potential exceptions.
Java uses a syntax that allows you to politely tell the client programmer that a method may throw an exception, and then the client programmer can handle it accordingly. Such an exception indicates. It is part of the method declaration, immediately following the formal parameter list.
Exercise 8
/* Write a class with a method that throws an exception of the type created * in Exercise 4. Try compiling it without an exception specification to see * what the compiler says. Add the appropriate exception specification. Try * out your class and its exception inside a try-catch clause. */ class Test8 { public static void f() throws Exception4 { System.out.println("f()"); throw new Exception4("Ouch from f()"); } } public class No8Ex { public static void main(String[] args) { try { Test8 t = new Test8(); t.f(); } catch(Exception4 e) { System.err.println("Caught Exception4"); e.printStackTrace(); e.showS(); } } } ============================================================ f() Exception4() Message from Exception4: Ouch from f() Caught Exception4 Chapter XII exception handling.Exception4: Ouch from f() at Chapter 12 exception handling.Test8.f(No8Ex.java:13) at Chapter 12 exception handling.No8Ex.main(No8Ex.java:21)
12.6 capture all exceptions
The base class Exception that caught the Exception
Put it at the end of the handler list in case it catches the exception before other handlers
Exception does not have much specific information. You can call its base class Throwable inheritance method:
String getMessage()
String getLocalizeMessage()
To get the details, or to express the details in the local language.
String toString()
Return a brief description of Throwable. If there is detailed information, it will also be included:
void printStrackTree() output to standard error
void printStackTree(PrintStream) select PrintStream as the output stream
void printStackTree(java.io.PrintWriter) select jav io. Printwriter is the output stream
Print Throwable and Throwable's call stack trace "take you to the exception throw point" method call sequence
Exercise 9
/* Create three new types of exceptions. Write a class with a method that * throws all three. In main(), call the method but only use a single catch * clause that will catch all three types of exceptions. */ class ExceptionA extends Exception { ExceptionA(String msg) { super(msg); } } class ExceptionB extends Exception { ExceptionB(String msg) { super(msg); } } class ExceptionC extends Exception { ExceptionC(String msg) { super(msg); } } public class No9Ex { public static void f(int x) throws ExceptionA, ExceptionB, ExceptionC { if(x < 0) throw new ExceptionA("x < 0"); if(x == 0) throw new ExceptionB("x == 0"); if(x > 0) throw new ExceptionC("x > 0"); } public static void main(String[] args) { try { // f(0); f(1); f(-1); // will catch any Exception type: } catch(Exception e) { System.out.println("Caught Exception"); e.printStackTrace(System.out); } } } ====================================================================Caught Exception Chapter XII exception handling.ExceptionC: x > 0 at Chapter XII exception handling.No9Ex.f(No9Ex.java:24) at Chapter XII exception handling.No9Ex.main(No9Ex.java:29)
12.6.1 stack track
The information provided by the printStrackTrace () method can be accessed directly through the getStackTree () method, which returns an array of elements in the stack track. Each element represents a frame of the stack, element 0 represents the top element of the stack, the last method call in the call sequence, and the last element is the first method call in the call sequence.
12.6.1 re throw exception
Throwing the exception again will throw the exception to the exception handler in the upper environment. The PrintStackTrace() method displays the call stack of the original exception throwing point instead of the information of the re throwing point.
Using fillInStackTrace (), returns a Throwable object. The information that the current stack information is filled with is the top note of the original exception object. The information about the original exception point is missing, and the rest is information related to the new throw point.
There is no need to worry about the cleaning of exception objects. They are all objects created by new on the heap, and they will be cleaned up automatically during the garbage collection period
12.6.3 abnormal chain
If you want to throw another exception after catching one exception and want to save the original exception information, it is called exception chain
All Throwable s can accept a cause object as a parameter. Cause is used to represent the original exception, which is passed to the new exception.
Three basic exception classes provide parameter constructors with cause:
- Error the Java virtual machine reports a system error
- Exception
- RuntimeException
If you want to connect other types, you should use the initCause() method
Exercise 10
/* Create a class with two methods, f() and g(). In g(), throw an exception of * a new type that you define. In f(), call g(), catch its exception and, in the * catch clause, throw a different exception (of a second type that you define). * Test your code in main(). */ class GException extends Exception { GException(String s) { super(s); } } class HException extends Exception { HException(String s) { super(s); } } public class No10Ex { static void f() { try { try { g(); } catch(GException ge) { System.out.println("Caught GException in f inner try"); ge.printStackTrace(); throw new HException("from f(), inner try"); } } catch(HException he) { System.out.println("Caught HException in f() outer try"); he.printStackTrace(System.out); } } static void g() throws GException { throw new GException("from g()"); } public static void main(String[] args) { f(); } } ====================================================================== Caught GException in f inner try Caught HException in f() outer try Chapter XII exception handling.HException: from f(), inner try at Chapter XII exception handling.No10Ex.f(No10Ex.java:25) at Chapter XII exception handling.No10Ex.main(No10Ex.java:36) Chapter XII exception handling.GException: from g() at Chapter XII exception handling.No10Ex.g(No10Ex.java:33) at Chapter XII exception handling.No10Ex.f(No10Ex.java:21) at Chapter XII exception handling.No10Ex.main(No10Ex.java:36)
Exercise 11
// TIJ4 Chapter Exceptions, Exercise 11, page 468 /* Repeat the previous exercise, but inside the catch clause, wrap g()'s * exception in a RuntimeException. */ public class No11Ex { static void f() { try { g(); } catch(GException ge) { System.out.println("Caught GException in f try"); ge.printStackTrace(); throw new RuntimeException(ge); } } static void g() throws GException { throw new GException("from g()"); } public static void main(String[] args) { f(); } } ============================================================== Caught GException in f try Chapter XII exception handling.GException: from g() at Chapter XII exception handling.No11Ex.g(No11Ex.java:20) at Chapter XII exception handling.No11Ex.f(No11Ex.java:12) at Chapter XII exception handling.No11Ex.main(No11Ex.java:23) Exception in thread "main" java.lang.RuntimeException: Chapter XII exception handling.GException: from g() at Chapter XII exception handling.No11Ex.f(No11Ex.java:16) at Chapter XII exception handling.No11Ex.main(No11Ex.java:23) Caused by: Chapter XII exception handling.GException: from g() at Chapter XII exception handling.No11Ex.g(No11Ex.java:20) at Chapter XII exception handling.No11Ex.f(No11Ex.java:12) ... 1 more
12.7 Java standard exception
The Java class Throwable is used to represent any class that can be thrown as an exception.
Two types:
- Error is used to indicate compile time and system errors
- The basic types that can be thrown by Exception, Java class libraries, user methods and runtime faults may throw Exception type exceptions.
12.7.1 special case: RuntimeException
Java's standard runtime checks whether each reference passed to a method is null, so you don't have to check whether each reference passed to a method is null
There are many exceptions that don't have to be thrown out of the virtual machine when it runs. These exceptions are inherited from RuntimeException, "unchecked exception". This exception is an error and will be automatically caught, so you don't have to do it yourself.
Exceptions of RuntimeException (and its subclasses) can only be ignored in the code, and the handling of other types of exceptions is enforced by the compiler. The reason is that RuntimeException represents a programming error:
- An unexpected error, a null reference you passed in from outside your control
- Errors checked in code progress.
Exceptions are designed
- Handle some annoying runtime errors caused by factors other than code control
- Some editors were found unable to detect ethical programming errors
12.8 cleaning with finally
Whether the exception in the try block is thrown or not, it can be executed. This usually applies to situations other than memory reclamation
12.8.1 what is finally used for
Finally is very important for languages without garbage collection and destructors (functions called when objects are no longer used, C + +). It is the programmer's guarantee that no matter what happens in the try block, the memory will always be released. When can Java be used finally?
When resources other than memory resources are to be restored to their initial state, the finally statement is used
- Open files or network connections
- Draw graphics on the screen
- A switch in the outside world
When the exception is not caught by the current exception handler, the exception handling mechanism will also execute the finally statement before jumping to a higher-level exception handler. When the break and continue statements are involved, the finally statement will also be executed.
Exercise 13
/* Modify Exercise 9 by adding a finally clause. Verify that your * finally clause is executed, even if a NullPointerException is thrown. */ class ExceptionA extends Exception { ExceptionA(String msg) { super(msg); } } class ExceptionB extends Exception { ExceptionB(String msg) { super(msg); } } class ExceptionC extends Exception { ExceptionC(String msg) { super(msg); } } public class No13Ex { // array element will be initialized to null: private static Integer[] x = new Integer[1]; public static void f(int x) throws ExceptionA, ExceptionB, ExceptionC { if(x < 0) throw new ExceptionA("x < 0"); if(x == 0) throw new ExceptionB("x == 0"); if(x > 0) throw new ExceptionC("x > 0"); } public static void main(String[] args) { try { // to throw NullPointerException: f(x[0]); f(0); f(1); f(-1); // will catch any Exception type: } catch(Exception e) { System.out.println("Caught Exception"); e.printStackTrace(System.out); } finally { System.out.println("made it to finally"); } } } ========================================================================= Caught Exception Chapter XII exception handling.ExceptionB: x == 0 at Chapter XII exception handling.No13Ex.f(No13Ex.java:26) at Chapter XII exception handling.No13Ex.main(No13Ex.java:33) made it to finally
Exercise 14
// Show that the OnOffSwitch.java can fail by throwing a // RuntimeException inside the try block. public class OnOffSwitch14 { private static Switch sw = new Switch(); static Integer[] x = new Integer[1]; public static void f(int i) throws OnOffException1, OnOffException2 {} public static void main(String[] args) { try { sw.on(); // Code that can throw RuntimeException // and leave Switch on: f(x[0]); sw.off(); } catch(OnOffException1 e) { System.out.println("OnOffException1"); sw.off(); } catch(OnOffException2 e) { System.out.println("OnOffException2"); sw.off(); } } }
Exercise 15
// Show that WithFinally.java doesn't fail by throwing a // RuntimeException inside the try block. public class WithFinally15 { private static Switch sw = new Switch(); // set up x[0] = null: private static Integer[] x = new Integer[1]; public static void f(int i) throws OnOffException1, OnOffException2 {} public static void main(String[] args) { try { sw.on(); // Code to throw NullPointerException: f(x[0]); } catch(OnOffException1 e) { System.out.println("OnOffException1"); } catch(OnOffException2 e) { System.out.println("OnOffException2"); } finally { sw.off(); } } }
12.8.2 use finally in return
Because the finally clause is always executed, multiple points can be returned in a method, and it can ensure that important cleaning work will still be executed.
18.3.3 defect: abnormal loss
Java's exception implementation is also flawed. Flag of program error,
This happens with some special final clause
- There is no catch in the inner layer, and the try statement in the inner layer is directly final
- final clause return even if an exception is thrown, no output will be generated
Exercise 18
// Add a second level of exception loss to LostMessage.java so that the // HoHumException is itself replaced by a third exception. class VeryImportantException extends Exception { public String toString() { return "A very important exception!"; } } class HoHumException extends Exception { public String toString() { return "A trivial exception"; } } class MeaninglessException extends Exception { public String toString() { return "A meaningless exception"; } } public class No18Ex { void f() throws VeryImportantException { throw new VeryImportantException(); } void dispose() throws HoHumException { throw new HoHumException(); } void eliminate() throws MeaninglessException { throw new MeaninglessException(); } public static void main(String[] args) { try { No18Ex lm = new No18Ex(); try { try { lm.f(); lm.dispose(); } finally { lm.eliminate(); } } catch(Exception e) { System.out.println(e); } } catch(Exception e) { System.out.println(e); } } } ========================================================== A meaningless exception
Exercise 19
public class LostMessageFound19 { void f() throws VeryImportantException { throw new VeryImportantException(); } void dispose() throws HoHumException { throw new HoHumException(); } public static void main(String[] args) { try { LostMessageFound19 lmf = new LostMessageFound19(); try { lmf.f(); } catch(Exception e) { System.out.println(e); } finally { lmf.dispose(); } } catch(Exception e) { System.out.println(e); } } } A very important exception! A trivial exception
12.9 limitation of exceptions
When overriding a method, only those exceptions listed in the exception description of its base class method can be thrown.
This means that when the code used by the base class is applied to its derived class objects, it can work (the basic concept of object-oriented):
-
The method declaration will throw an exception, but it doesn't. this way allows you to force users to catch exceptions that may be added in the overridden event () version, so it's reasonable. The same holds for abstract methods.
-
If a class inherits the base class and implements an interface, the interface cannot add or change exceptions to the existing methods in the base class
-
If the method defined in the interface is not from the base class, there is no problem with what kind of exception the method throws. Or implement an existing method without throwing an exception
-
There are no restrictions on constructors. Constructors of inherited classes can throw any exception, regardless of the exception thrown by the base class constructor, but the base class constructor exception must be included
-
Derived class constructors cannot catch base class constructor exceptions
-
By forcing the derived class to follow the exception description of the base class method, the replaceability of the object is guaranteed
-
It can be transformed upward into a base class, and the compiler will require you to catch exceptions of the base class, which can produce more mandatory exception class code
In the inheritance process, the compiler will enforce exceptions, but the exception description itself does not belong to a part of the method type, and the method is not overloaded based on the exception description. An exception that appears in the exception description of the base class method does not necessarily appear in the exception description of the derived class method. In the process of inheritance and coverage, the method of the base class must appear in the derived class. "The exception of a specific method indicates that the interface does not become larger but smaller, which is opposite to the situation when the interface and class inherit“
Exercise 20
/* MOdify StormyInning.java by adding an UmpireArgument exception type * and methods that throw this exception. Test the modified hierarchy. */ // Overridden methods may throw only the exceptions // specified in their base-class versions, or exceptions // derived from the base-class exceptions. import Chapter X internal class.No20; class BaseballException extends Exception {} class Foul extends BaseballException {} class Strike extends BaseballException {} class UmpireArgument extends BaseballException {} class ThrownFromGame extends UmpireArgument {} abstract class Inning { public Inning() throws BaseballException {} public void event() throws BaseballException { // Doesn't actually have to throw anything } public abstract void atBat() throws Strike, Foul, UmpireArgument; public void questionableCall() throws UmpireArgument {} public void walk() {} // Throws no checked exceptions } class StormException extends Exception {} class RainedOut extends StormException {} class PopFoul extends Foul {} interface Storm { public void event() throws RainedOut; public void rainHard() throws RainedOut; } public class No20StormyInning extends Inning implements Storm { // OK to add new exceptions for constructors, but you // must deal with the base constructor exceptions: public No20StormyInning() throws UmpireArgument, RainedOut, BaseballException {} public No20StormyInning(String s) throws Foul, BaseballException {} // Regular methods must comform to base class: //! void walk() throws PopFoul {} // Compile error // Interface CANNOT add exceptions to existing // methods from the base class: //! public void event() throws RainedOut {} // If method doesn't already exist in the // base class, the exception is OK: public void rainHard() throws RainedOut {} // You can choose to not throw any exceptions, // even if the base class version does: public void event() {} // Overridden methods can throw inherited exceptions: public void atBat() throws PopFoul, ThrownFromGame { throw new ThrownFromGame(); } public void questionableCall() throws UmpireArgument { throw new UmpireArgument(); } public static void main(String[] args) { try { No20StormyInning si = new No20StormyInning(); si.atBat(); si.questionableCall(); } catch(PopFoul e) { System.out.println("Pop foul"); } catch(UmpireArgument e) { System.out.println("Umpire argument (StormyInning20)"); // } catch(ThrownFromGame e) { // System.out.println("Thrown from game"); } catch(RainedOut e) { System.out.println("Rained out"); } catch(BaseballException e) { System.out.println("Generic baseball exception"); } // Strike not thrown in derived version. try { // What happens if you upcast? Inning i = new No20StormyInning(); i.atBat(); // You must catch the exceptions from // the base-class version of the method: } catch(Strike e) { System.out.println("Strike"); } catch(Foul e) { System.out.println("Foul"); } catch(ThrownFromGame e) { System.out.println("Thrown from game (Inning)"); } catch(RainedOut e) { System.out.println("Rained out"); } catch(BaseballException e) { System.out.println("Generic baseball exception"); } } } ======================================================================== Umpire argument (StormyInning20) Thrown from game (Inning)
12.10 constructor
If an exception occurs, can everything be cleaned up correctly? In most cases, it is very safe, but when it comes to the constructor, the problem arises. The constructor will set the object to a safe initial state. Be careful when writing constructors. If the constructor throws an exception, it cannot be initialized well, resulting in the cleaning behavior may not work properly.
Handle objects that have failed constructors and need to be cleaned up. In order to handle this correctly, each constructor must be included in its own try finally statement, and each object construct must be followed by a try finally statement block to ensure cleanup.
Exercise 21
// Demonstrate that a derived-class constructor cannot catch exceptions thrown // by its base-class constructor. class BaseException extends Exception {} class Base { Base() throws BaseException { throw new BaseException(); } } class Derived extends Base { // BaseException must be caught (no way) or // declared to be thrown: Derived() throws BaseException { super(); // not this way, 'catch' without 'try' not allowed: // catch(BaseException e) {} // not this way either, because call to super // must be first statement in constructor: // try { // super(); // } catch(BaseException e) {} } } public class No21Derived { public static void main(String[] args) { try { Derived d = new Derived(); } catch(BaseException e) { System.out.println("BaseException caught in main()"); } } } ======================================================================== BaseException caught in main()
Exercise 22
/* Create a class called FailingConstructor with a constructor that might fail * partway through the construction process and throw an exception. In main(), * write code that properly guards against this failure. */ public class No22Ex { Integer[] ia = new Integer[2]; String s; No22Ex(String s) throws Exception { ia[0] = 0; ia[1] = 1; ia[2] = 2; this.s = s; } public static void main(String[] args) { try { No22Ex fc = new No22Ex("hi"); } catch(Exception e) { System.err.println("Caught Exception in main()"); e.printStackTrace(System.err); } finally { } } } =================================================================== Caught Exception in main() java.lang.ArrayIndexOutOfBoundsException: 2 at Chapter XII exception handling.No22Ex.<init>(No22Ex.java:13) at Chapter XII exception handling.No22Ex.main(No22Ex.java:18)
Exercise 23
/* Add a class with a dispose() method to the previous exercise. Modify * FailingConstructor so that the constructor creates one of these disposable * objects, after which the constructor might through an exception, after which * it creates a second disposable member object. Write code to properly guard * against failure, and in main() verify that all possible failure situations * are covered. */ // This solution satisfies the conditions called for in FailingConstructor23 // constructor, which catches its own exceptions. class Disposable { private static int counter = 0; private int id = counter++; private boolean disposed; Disposable() { disposed = false; } void dispose() { disposed = true; } String checkStatus() { return (id + " " + (disposed ? "disposed" : "not disposed")); } } public class No22FailingConstructor { private Integer[] ia = new Integer[2]; private static Disposable d0; private static Disposable d1; No22FailingConstructor() throws Exception { try { d0 = new Disposable(); try { ia[2] = 2; // causes exception thrown and // caught in middle try loop try { d1 = new Disposable(); } catch(Exception e) { System.out.println("Caught e in inner try loop"); e.printStackTrace(System.err); System.out.println("Failed to create d1"); } } catch(Exception e) { System.out.println("Caught e in middle try loop"); e.printStackTrace(System.err); System.out.println("Disposing d0"); d0.dispose(); // d0 would have been created } } catch(Exception e) { System.out.println("Caught e in outer try loop"); e.printStackTrace(System.err); System.out.println("Failed to create d0"); } } public static void main(String[] args) { try { // the constructor catches its own exceptions: No22FailingConstructor fc = new No22FailingConstructor(); } catch(Exception e) { System.err.println("Caught Exception in main()"); e.printStackTrace(System.err); } } } ========================================================= Caught e in middle try loop Disposing d0 java.lang.ArrayIndexOutOfBoundsException: 2 at Chapter XII exception handling.No22FailingConstructor.<init>(No22FailingConstructor.java:36) at Chapter XII exception handling.No22FailingConstructor.main(No22FailingConstructor.java:61)
Exercise 24
/* Add a dipsose() method to the FailingConstructor class and write code to properly use * this class. */ // Solution modeled from examples in text: import java.io.*; public class No24Ex { private BufferedReader in; public No24Ex(String fname) throws Exception { try { in = new BufferedReader(new FileReader(fname)); } catch(FileNotFoundException e) { System.out.println("Could not find file " + fname); throw e; } catch(Exception e) { try { in.close(); } catch(IOException e2) { System.out.println("in.close() failed"); } throw e; } } public String getLine() { String s; try { s = in.readLine(); } catch(IOException e) { throw new RuntimeException("readLine() failed"); } return s; } public void dispose() { try { in.close(); System.out.println("dispose() successful"); } catch(IOException e2) { throw new RuntimeException("in.close() failed"); } } public static void main(String[] args) { try { No24Ex fc = new No24Ex("No22Ex.java"); try { String s; int i = 1; while((s = fc.getLine()) != null) { // code to print to new file: // println(i + " " + s); // i++; } } catch(Exception e) { System.out.println("Exception caught in main()"); e.printStackTrace(System.err); } finally { fc.dispose(); } } catch(Exception e) { System.out.println("FailingConstructor22b construction failed"); } } } =================================================== Could not find file No22Ex.java FailingConstructor22b construction failed
12.11 abnormal matching
When throwing an exception, the exception handling system will find the nearest handler according to the code writing order. Once a matching handler is found, it assumes that the exception will be handled and then stops looking
Objects of derived classes can also match handlers of their base classes
You can't put the catch clause of the base class on the outside and the exception of the derived class on the inside, so the exception of the derived class can never be executed
/* Create a three-level hierarchy of exceptions. Now create a * base-class A with a method that throws an exception at the base * of your hierarchy. Inherit B from A and override the method so * it throws an exception at level two of your hierarchy. Repeat by * inheriting class C from B. In main(), create a C and upcast it * to A, then call the method. */ class LevelOneException extends Exception {} class LevelTwoException extends LevelOneException {} class LevelThreeException extends LevelTwoException {} class A { void f() throws LevelOneException { throw new LevelOneException(); } } class B extends A { void f() throws LevelTwoException { throw new LevelTwoException(); } } class C extends B { void f() throws LevelThreeException { throw new LevelThreeException(); } } public class No25Ex { public static void main(String[] args) { A a = new C(); try { a.f(); } catch(LevelThreeException e3) { System.out.println("Caught e3"); } catch(LevelTwoException e2) { System.out.println("Caught e2"); } catch(LevelOneException e1) { System.out.println("Caught e1"); } } } ================================================================= Caught e3
12.12 other options
The exception handling system is like a trap door, enabling you to abandon the normal execution sequence of the program.
Important rule: catch exceptions only if you know how to handle them
Important goal: separate the error handling code from where the error occurred
Exception checking will force you to assume catch statements when you may not be ready to handle errors, resulting in a devouring is allowed error. Java is a strong static language, which does type checking at compile time.
Study the abnormalities examined and their complications, and what methods are taken to solve the problem
Java is a strongly typed language (a language that does type checking at compile time), so you should be skeptical about type checking. (all models are wrong, but they are useful)
- It's not whether the compiler forces the programmer to handle errors, but a consistent model that uses exceptions to report errors
- It doesn't depend on when to check, but there must be type checking, that is, the program must be forced to use the correct type. It doesn't matter whether this force is imposed at compile time or run time
By passing the exception to the console, you don't have to write a try catch clause in main ()
Convert the "checked exception" into "non persistent exception", and wrap the "checked exception" into RuntimeException.
Shield the checked exceptions from this function
Exercise 27
// Modify Exercise 3 to convert the exception to a Runtime Exception. public class No27Ex { private static int[] ia = new int[2]; public static void main(String[] args) { try { ia[2] = 3; } catch(ArrayIndexOutOfBoundsException e) { // convert to RuntimeException: throw new RuntimeException(e); } } }
Exercise 28
/* Modify Exercise 4 so that the custom exception class inherits from * RuntimeException, and show that the compiler allows you to leave * out the try block. */ class Exception28 extends RuntimeException { private String msg; Exception28(String msg) { super(msg); System.out.println("Exception28()"); this.msg = msg; } protected void showS() { System.out.println("Message from Exception4: " + msg); } } public class Ex28 { public static void f() throws Exception28 { System.out.println("f()"); throw new Exception28("Ouch from f()"); } public static void main(String[] args) { f(); } } ============================================================== f() Exception28() Exception in thread "main" Chapter XII exception handling.Exception28: Ouch from f() at Chapter XII exception handling.No28Ex.f(No28Ex.java:23) at Chapter XII exception handling.No28Ex.main(No28Ex.java:26)
Exercise 29
/* Modify all the exception types in StormyInning.java so that they extend * RuntimeException, and show that no exception specifications or try blocks * are necessary. Remove the '//!' comments and show how the methods can be * compiled without specifications. */ class BaseballException extends RuntimeException {} class Foul extends RuntimeException {} class Strike extends RuntimeException {} abstract class Inning { public Inning() {} public void event() {} public abstract void atBat(); public void walk() {} } class StormException extends RuntimeException {} class RainedOut extends RuntimeException {} class PopFoul extends RuntimeException {} interface Storm { public void event(); public void rainHard(); } public class StormyInning29 extends Inning implements Storm { public StormyInning29() {} public StormyInning29(String s) {} public void walk() {} public void event() {} public void rainHard() {} public void atBat() {} public static void main(String[] args) { StormyInning29 si = new StormyInning29(); si.atBat(); // What happens if you upcast? Inning i = new StormyInning29(); i.atBat(); } }
Exercise 30
/* Modify Human.java so that the exceptions inherit from * RuntimeException. Modify main() so that the technique * in TurnOffChecking.java is used to handle the different * types of exceptions. */ class Annoyance extends RuntimeException {} class Sneeze extends Annoyance {} class WrapCheckedExceptions { void throwRuntimeException(int type) { try { switch(type) { case(0): throw new Annoyance(); case(1): throw new Sneeze(); case(2): throw new RuntimeException("Where am I?"); default: return; } } catch(Exception e) { // Adapt to unchecked: throw new RuntimeException(e); } } } public class No30Ex { public static void main(String[] args) { WrapCheckedExceptions wce = new WrapCheckedExceptions(); for(int i = 0; i < 3; i++) try { if(i < 3) wce.throwRuntimeException(i); else throw new RuntimeException(); } catch(RuntimeException re) { try { throw re.getCause(); } catch(Sneeze e) { System.out.print("Sneeze: " + e); } catch(Annoyance e) { System.out.println("Annoyance: " + e); } catch(Throwable e) { System.out.println("Throwable: " + e); } } } } ===================================================================== Annoyance: Chapter XII exception handling.Annoyance Sneeze: Chapter XII exception handling.SneezeThrowable: java.lang.RuntimeException: Where am I?
12.13 abnormal use guide
12.14 summary
If you don't use exceptions, you can only do a limited amount of work. The essence of abnormal function reporting is that recovery may not account for 10%
, recovery just expands the exception stack.