1. Handle errors

Effective reasoning is needed to deal with mistakes;

1.1 Anomaly Classification

  • Exception:

Let me first explain what an exception is. An exception is a program exception event caused by external problems (such as hardware errors and input errors) during the running of a program. (In Java and other object-oriented programming languages) an exception is itself an object, and to generate an exception is to generate an exception object. In plain English, an unexpected event that occurs when a program is running and prevents the program from executing as expected is an exception.

  • Exception objects in Java are derived from an instance of the Throwable class (there are some generic exceptions built into the Java standard pants that use Throwable as their top-level parent). Throwable also derives the Error and Exception classes;

Java exception hierarchy diagram:

  • Error (instances of the Error class and its subclasses) : Java runtime system internal errors or resource exhaustion errors (errors of the JVM itself); Such errors cannot be handled by programmers in code and should not be thrown;
  • Exception(Exception and its subclasses) : represents various unexpected events sent while the program is running; Can be used by Java exception handling mechanism, is the core of exception handling;
    • RuntimeException: Exception caused by a program error;
    • IOException: Exceptions caused by problems such as I/O errors;

Unchecked: All exceptions that derive from the Error or RuntimeException class; Javac does not prompt or discover such exceptions during compilation and does not require the program to handle them. So we can write code to handle (using try… catch… Finally), can also not handle exceptions; These exceptions should be corrected by code rather than handled by exception handlers (the result of code handling is much more efficient than the result of exception handling); Such exceptions are most likely due to poorly written code; Such as zero error ArithmeticException, casts error ClassCastException error, array index ArrayIndexOutOfBoundsException seams, NullPointerException and so on; Checked: exceptions other than those that are not checked (exceptions other than Error and RuntimeException); Javac forces the programmer to do preparatory work for such exceptions (using try… catch… Finally or throws); The compiler fails if it is either caught and processed in a try-catch statement or thrown with a throws clause. Such exceptions are usually caused by the environment in which the program is running; Because programs can be run in all kinds of unknown environments, and the programmer has no way of interfering with how the user uses the program, the programmer should always be prepared for such exceptions. Such as SQLException, IOException, ClassNotFoundException, etc.;

  • Read the abnormalAn exception is thrown when a function is executed, and the function isCall hierarchyTo formThe call stackIf an exception occurs in a function, all its caller will be affected by the exception. When these affected functions are output with exception information, an exception tracing stack is formed.The point where an exception first occurs is called the exception throw point;

1.2 Declare the checked exception

A method needs to tell the compiler not only what value to return, but also what errors are likely to occur; When writing your own method, you do not have to declare every exception that can be thrown, but you should throw an exception when: (1) calling a method that throws the checked exception; For example: FileInputStream constructor; (2) An error is found during program operation, and a checked exception is thrown by a throw statement; (3) the program errors, such as: a [1] = 0, throw ArrayIndexOutOfBoundException; (4) Internal errors occur in the Java VIRTUAL machine and runtime library;

  • The programmer calling this method must be told that it is possible to throw an exception. If no handler catches this exception, the current thread of execution terminates;
  • In summary, a method must declare all checked exceptions that can be thrown, not checked exceptions that should either be uncontrollable (Error) or should be avoided (RuntimeException); If the method does not declare all possible checked exceptions, the compiler issues an error message;
  • Note: a method in a subclass that overrides a parent class cannot throw an exception more general than the parent class. The method either does not throw an exception or throws a more specific exception. To put it more simply, when a subclass overrides a function with a throws declaration of its parent class, the exception declared by the subclass must be within the scope of the parent class exception. The exception handler used to handle the parent class’s throws method must also apply to the subclass’s throws method. This is to support polymorphism; For example, if the parent method throws two exceptions, the subclass cannot throws3 or more exceptions. The parent class throws IOException, and the subclass must throw IOException or a subclass of IOException.

1.3 Throwing an Exception

  • When an exception is thrown, the first consideration is what type of exception is thrown. The throw statement is as follows (for example, reading a file throws an exception) :
// Throw new EOFException; EOFException e = new EOFException(); throw e; // Full form StringreadData(Scanner in) throws EOFException{
    //...
    while(/ /...). {if(! in.hasNext()) {if(n < len) {
                String gripe = "Content-length:" + len + ", Received:"+ n; throw new EOFException(gripe); }}}return s;
}
Copy the code
  • Throw for an existing exception class:

① Find a suitable exception class; ② Create an object of this class. ③ Throw the object; Note: Once a method throws an exception, the method cannot be returned to the caller;

1.4 Creating exception Classes

If a standard exception class cannot be found to clearly describe or solve the problem, you need to create your own exception class. Simply define a class derived from Exception or a class derived from a subclass of Exception.

// When the exception class is defined, it can be used normally. The derived exception usually has a default constructor and a constructor with detailed description (see JDK source code for the constructor). Defines a class derived from IOException public Class FileFormatException extends IOException {publicFileFormatException(){ } public FileFormatException(String gripe){ super(gripe); }}Copy the code

2. Catch exceptions

Throwing exceptions is simple, while catching exceptions is more complex and requires careful planning; Some code must catch exceptions;

2.1 Catching Exceptions

If an exception occurs and is not caught, the program will terminate execution. To catch an exception, a try/catch block must be set. The simplest try statement is:

try{
    code
    more code
    more code
}catch (ExceptionType e){
    handler for this type} // If any code in the try block throws an exception class specified in the catch clause, the program skips the rest of the try block and executes the code in the catch clause. If a method throws an exception that has no corresponding type in the catch statement, the method exits immediately (designers need to take exceptions into account).Copy the code
  • Typical program code for reading data:
// Use exception capture to handle exceptions public voidread(String filename){
    try{
        InputStream in = new FileInputStream(filename);
        int b;
        while((b = in.read()) ! = -1){ //process input } }catch (IOException exception){ exception.printStackTrace(); }} // Handle exceptions by throwing them public voidread(String filename) throws IOException{
    InputStream in = new FileInputStream(filename);
    int b;
    while((b = in.read()) ! = -1){ //process input } }Copy the code
  • In general, you should catch those exceptions that you know how to handle, and pass those that you don’t!!
  • Exception, the method in the superclass does not throw an exception, so the method overriding the superclass method in the subclass cannot throw an exception, if there is an exception must be caught;
  • Do not allow exception classes in a subclass beyond the range listed by superclass methods in the throws specifier;

2.2 Catching multiple exceptions

Multiple exception types can be caught in a try block and handled differently for different types of exceptions. You can use a separate catch clause for each exception type as follows:

Try {//code that might throw exception}catch (FileNotFoundException e){LLDB message (); //emergency actionforMissing files}catch (UnknownHostException e){LLDB etClass().getName(); //emergency actionfor unknown hosts
}catch (IOException e){
    //emergency action forAll other I/O problems} // The same catch clause can catch multiple exception types; The catch clause can be combined when the exception action is the same.Copy the code
  • Note: When multiple exceptions are caught, the exception variable is implicitly final;
  • Note: Catching multiple exceptions not only makes your code look simpler, it also makes it more efficient; The generated bytecode only packages a block of code corresponding to a common catch clause; Since exception matching is performed from top to bottom, the first catch to be matched is executed. Therefore, when there are multiple catch matches, the child exception should be placed first and the parent exception should be placed later.

2.3 Throw exceptions and exception chains again

The catch clause can throw an exception to change the type of the exception. Scenario: If a subsystem is called, and you don’t care about the details of the subsystem error, just want to know whether the subsystem error;

Try {// Access the database}catch(SQLException e){throw new ServletException("database error:"+ e.getMessage()); } // Better way: Set the original exception to a new exception // It is recommended to use this technique, which throws advanced exceptions for the subsystem, Try {//access the database}catch (SQLException e){Throwable se = new ServletException("database error"); se.initCause(e); throw se; } // After catching the exception, the caller can retrieve the original exception with the following statement: Throwable e = se.getCause();Copy the code
  • If a checked exception occurs in a method, it is not allowed to be thrown. At this point we can catch the checked exception and wrap it as a runtime exception;
// Try {// Access the database}catch (Exception e){logger.log(level, message, e); throw e; }Copy the code

The finally clause 2.4

  • Background: After the code throws an exception, it terminates the processing of the rest of the code in the method and exits the execution of the method; If this method obtains some local resources, the local resources must be cleaned up before exiting the method. For example, close a file or disconnect the network. ;
  • Solution:
    1. Catch and rethrow all exceptions: all allocated resources are clear in both normal and exception code;
    2. Finally clause: The code in the finally clause is executed whether or not an exception is caught; Such as:
// This program will close the file InputStream in all casesin= new FileInputStream(...) ; try{ //code that might throw exception }catch(IOException e){ //show error message }finally{ in.close(); }Copy the code

If the code does not throw an exception, all the code in the try and finally blocks will be executed. (2) Execute the code in the catch clause before the exception is thrown in the try, the code in the catch clause that matches the exception, and the code in the finally clause. (3) Execute the code in the finally clause before throwing an exception in the try clause.

  • In the case of only try and finally statements, the code in finally is executed whether or not an exception occurs ina try;
// Closing a resource with the finally clause is a good option for InputStreamin = ...;
try{
    //code might throw exception
}finally {
    in.close();
}
Copy the code
  • Decoupling try/catch and try/finally blocks is strongly recommended (to improve code clarity), such as:
/** * Decouples try/catch and try/finally blocks: * This design is not only clear, but also has the ability to report errors in the finally clause */ InputStreamin=... ; Try {//code that might throw exceptions}finally{in.close(); } }catch(IOException e){ //show error message }Copy the code
  • Warning: When the finally clause contains a return statement: When the try clause contains a return statement and the try clause exits with a return statement; The return in the finally clause is executed and overrides the result of the return statement in the try clause. In short, after a return in the try clause executes, a return in the finally clause executes and overrides the return statement in the try clause. Such as:
/** * when n=2,return0; * If f(2) is called, the try block evaluates to r = 4 and executesreturnHowever, the finally clause must be executed before the method actually returns; The finally clause causes the method to return 0, * overwriting the original return value of 4; Try... catch... In the finallyreturnAs long as it can be executed, it is executed. They write a return value to the same memory address (assuming address 0x80). The last one to be executed overwrites the first one, and the return value that was actually taken by the caller is the last one to be written. * @param n * @return
 */
public static int f(int n){
    try{
        int r = n * n;
        return n;
    }finally {
        if(n == 2)
            return0; }}Copy the code
  • Note: a return in finally overrides a return ina try and catch (if any), and suppresses exceptions ina try and catch (if any). Similarly, exceptions in finally override exceptions in try and catch (if any); Do not use returns in finally. (Try to write all returns at the end of a function instead of a try… catch … In the finally); ② Do not throw exceptions in finally; 3) Lighten the task of finally by not doing anything else in finally. Finally blocks are best used only to release resources.
  • Question: What if an exception is thrown when a resource is closed in the finally clause? If there is an exception in the try clause, the exception in the finally clause overwrites the exception in the try clause. If you write your code to throw exceptions in both try and finally, it becomes very cumbersome;

2.5 Try Statements with Resources

Disable resources in Java SE 7;

  • AutoCloseable interface:
    • Throws Exception with void close();
  • Closeable: a subinterface of AutoCloseable that also contains the close method, which throws an IOException;
  • The simplest form of a try statement with resources (try-with-resources) is:
Res.close () try(Resource res =...) { //work with res }Copy the code
  • Example of reading all words in a file:
Res.close () is automatically called when this block exits, or when an exception exists; As if using the finally block; try(Scannerin = new Scanner(new FileInputStream("/usr/share/dict/words"), "UTF-8")) {while(in.hasNext()){ System.out.println(in.next()); }} // With multiple resources: try(Scannerin = new Scanner(new FileInputStream("/usr/share/dict/words"), "UTF-8");
    PrintWriter out = new PrintWriter("out.txt")) {while(in.hasNext()){ out.println(in.next().toUpperCase()); }}Copy the code
  • In a try statement with a resource, the exception thrown by the close method is “suppressed” and the original exception is rethrown;
  • Of course, try statements with resources can also have catch and finally clauses. These clauses are executed after the resource is closed.

2.6 Analyzing stack trace elements

Public class StackTraceTest {public static int factorial(int n){system.out.println ("factorial(" + n + "):");
        Throwable t = new Throwable();
        StackTraceElement[] frames = t.getStackTrace();
        for(StackTraceElement f: frames)
            System.out.println(f);
        int r;
        if(n <= 1)
            r = 1;
        else
            r = n * factorial(n - 1);
        System.out.println("return " + r);
        return r;
    }

    public static void main(String[] args){
        Throwable t = new Throwable();
        StringWriter out = new StringWriter();
        t.printStackTrace(new PrintWriter(out));
        String description = out.toString();
        System.out.println("description:" + description);

//        Scanner in = new Scanner(System.in);
//        System.out.print("Enter n:"); // int n = in.nextInt(); // factorial(n); }}Copy the code

3. Techniques for using exception mechanisms

  1. Exception handling is no substitute for simple testing: catching exceptions takes much longer than executing simple tests, so the basic rules for using exceptions are: use exception mechanisms only in exceptional cases;
  2. Don’t overelaborate exceptions:
  3. Utilize exception hierarchies:
    • Don’t just throw RuntimeException: find a more appropriate subclass or create your own exception class;
    • Don’t just catch Throwable exceptions, which will make your program code harder to read and maintain.
    • Do not throw exceptions for logical errors;
    • Don’t hesitate to convert one exception into another that is more appropriate: When parsing an integer in a file, catch the NumberFormatException exception and then convert it to IOException or a subclass of MySubsystemException;
  4. Don’t suppress exceptions: If you think exceptions are important, you should handle them;
  5. When detecting errors, it is better to be “harsh” than “laissez-faire” : it is better to throw an exception when calling a method with invalid arguments than to return dummy values; Because virtual values raise exceptions later in the code, exception handling and Bug finding are more difficult; You throw an exception anyway;
  6. Don’t be shy about passing exceptions: Some exceptions need to be thrown, and it’s better to have a high-level method to notify the user that an error has occurred, or to discard unsuccessful commands.
  • “Throw early, catch late”;

4. Use assertions

4.1 The concept of assertions

First I need to know what assertions are; Assertions are a mechanism that allows checking statements to be inserted into the code during testing; When the code is published, these inserted checks are automatically removed;

  • The keyword assert:
    • Assert conditions:

    The result is false, raising an AssertError exception;

    • Assert conditions: expressions;

    If the result is false, the expression is passed to the constructor of the AssertionError and converted to a message string;

  • The sole purpose of the “expression” part is to produce a string message. The AssertionError object does not store the value of the expression, so it cannot be retrieved later;
  • By default, assertions are disabled; You can be enabled at run time with the add -enableassertions or -EA option (this parameter is available in the VM Options bar of the Configuration option in IDEA);

4.2 Using assertions to complete parameter checking

  • Use scenarios for assertions:
    • Assertion failures are fatal and unrecoverable errors;
    • Assertion checking is only used in the development and test phases;

5. Record logs

  • Background: Using system.out.println () to do auxiliary observation program run more troublesome;
  • Advantages: simple to use ~ ha ha ha

5.1 Basic Logs

  • Generate simple logs:
    • Call the info method with the global Logger: Logger.getGlobal().info(“File->Open menu item selected”);
    • Cancel all logging: logger.getGlobal ().setlevel (level.off);

5.2 Advanced Logs

Instead of logging everything into a global logger when developing software, you can customize the logger.

  • The getLogger method creates or retrieves a logger:

    private static final Logger myLogger = Logger.getLogger(“com.basicofjava”); Loggers that are not referenced by any variables may be garbage collected; A static variable can store a reference to the logger to prevent it from being reclaimed;

6. Debugging skills

Background: Suppose you wrote a program, caught all exceptions and handled them properly, and then ran the program, but still had problems. What now?

  • Some debugging tips:
    1. Println (“x=” + x); system.out.println (“x=” + x); Logger.getGlobal().info(“x=” + x);
    2. Each class has a separate main method to unit test: create a few objects to call all the methods and check for errors;
    3. Using the JUnit framework: junit.org/junit5/
    4. Logging Proxy:
    5. Take advantage of the printStackTrace method provided by the Throwable class (which gets the stack from any exception object) : you can catch the printStackTrace() or insert Thread.dumpstack () directly anywhere in the code;
    6. Generally, the stack trace is displayed on system.err; You can also send it to a file using the printStackTrace(PrintWriter s) method; Such as:
StringWriter out = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(out));
String description = out.toString();
System.out.println("description:" + description);
Copy the code
7....Copy the code

7. To summarize

There are three mechanisms for handling system errors in Java: ① throwing exceptions; ② Use assertions; (3) log;