Location>code7788 >text

Java exception explained (full text dry)

Popularity:658 ℃/2024-08-28 21:27:38

present (sb for a job etc)

Throwable

Throwable is the superclass of all errors and exceptions in the Java language.

Throwable contains two subclasses, Error and Exception, which are typically used to indicate that an exception has occurred.

Throwable contains a snapshot of the thread's execution stack at the time of its thread creation, and it provides interfaces such as printStackTrace() for obtaining information such as stack trace data.

Error

Error class and its subclasses: errors that cannot be handled by the program, indicating that a serious error has occurred in the running application.

This type of error generally indicates a problem with the JVM while the code is running. Usually there are

  • Virtual MachineError

  • NoClassDefFoundError

  • OutOfMemoryError: Out of Memory Error

  • *Error: stack overflow error.

The JVM terminates the thread when such errors occur. These errors are unchecked exceptions, non-code errors. Therefore, the application should not handle such errors when they occur. By Java convention, we are not supposed to implement any new Error subclasses!

Exception

Exceptions that can be caught and handled by the program itself.ExceptionThese exceptions are subdivided into two categories: runtime exceptions and compile-time exceptions.

  1. run-time exception (computing)(unchecked exceptions)

    • are RuntimeException class and its subclass exceptions, such as NullPointerException (null pointer exception), IndexOutOfBoundsException (subscript out of bounds exception), etc., these exceptions are unchecked exceptions, which the program can choose to catch to deal with, or not deal with. These exceptions are generally caused by program logic errors, the program should be from a logical point of view as far as possible to avoid the occurrence of such exceptions.

    • The thing about a runtime exception is that the Java compiler doesn't check for it; that is, when this type of exception is possible in a program, it will compile through even if you don't catch it with a try-catch statement or declare that you're throwing it with a throws clause.

  2. non-runtime exception(checked exceptions, compile-time exceptions)

    • are exceptions other than RuntimeException, which belong to the Exception class and its subclasses. From the program syntax point of view is the exception must be handled, if not handled, the program can not be compiled through. Such as IOException, SQLException, etc., as well as user-defined Exception exceptions, in general, do not custom check exceptions.

Common Abnormalities

Some exceptions are provided in Java to describe frequently occurring errors, for which some need to be caught and handled by the programmer or declared to be thrown, while others are automatically caught and handled by the Java Virtual Machine.Common Exception Classes in Java.

  • RuntimeException

    • Array index out-of-bounds exception. Thrown when the index value to the array is negative or greater than or equal to the array size.

    • Abnormal arithmetic conditions. For example, dividing integers by zero, etc.

    • Null Pointer Exception. This exception is thrown when an application attempts to use a null object where it is required. Examples include: calling an instance method of a null object, accessing a property of a null object, calculating the length of a null object, throwing null with a throw statement, etc.

    • Class not found exception. This exception is thrown when an application attempts to construct a class based on a class name in string form, and after traversing CLASSPAH cannot find a class file with the corresponding name.

    • Negative array length exception

    • Exceptions thrown by arrays containing incompatible values

    • Security anomalies

    • Illegal parameter exception

  • IOException

    • IOException: exceptions that may occur when manipulating input and output streams.

    • EOFException End of File Exception

    • FileNotFoundException File Not Found Exception

  • (sth. or sb) else

    • ClassCastException Type conversion exception class

    • ArrayStoreException Thrown by an array containing incompatible values.

    • SQLException Operation Database Exception Class

    • NoSuchFieldException Field Not Found Exception

    • NoSuchMethodException Thrown by method not found

    • NumberFormatException String to number exception thrown.

    • StringIndexOutOfBoundsException Thrown when string index is out of bounds.

    • IllegalAccessException Not Allowed to Access a Class Exception

    • InstantiationException Thrown when an application attempts to create an instance of a class using the newInstance() method of the Class class, and the specified class object cannot be instantiated

These exceptions are Java's built-in exception classes, but of course users can customize their own exception classes based on their business:

public class MyException extends RuntimeException {
    // unparameterized constructor
    public MyException() {}

    // Constructor with details
    public MyException(String message) {
        super(message);
    }

    // Constructor with the cause of this exception
    public MyException(Throwable cause) {
        super(cause);
    }

    // Constructors that contain both error messages and causes
    public MyException(String message, Throwable cause) {
        super(message, cause);
    }
}

Handling of exceptions

  • try-catch: want the program to continue to run after an exception, then it is used after the check statement:

  • throw: in the conditions of an exception within the method directly throw out the exception: the execution of the throw must have thrown an exception. It can be understood that the possible exceptions can be expected before programming, then:

if (the expected exception occurs) {
    throw new corresponding exception(); // can be a customized exception
} // You can also write the "output statement" in parentheses when the exception occurs.

That is, bothdiscoveriesAbnormal, again.deal withException.

BTW: this targeted declaration can only throw a single exception

  • throws: unlike the throw method, throws follows the method declaration and throws an exception that could occur using this method (or throws an exception after the current class that defines the variable where the exception could occur). It just finds the exception and doesn't handle it, leaving it to the caller of the method. And you can throw more than one exception at a time.

Common Methods for Exceptions

  1. getMessage(): Returns detailed information about the exception that occurred and, if necessary, some of the state variables at the time the exception was thrown.
  2. printStackTrace(): Outputs the exception stack in the standard error stream. This method is useful for printing detailed error messages because it shows the code execution path of the exception from the time it occurs to the time it is caught, but this method should not be called at any time.
  3. toString(): Returns a short description, including: the non-fully-qualified class name of Throwable, followed by the result of getMessage().
  4. getCause(): Returns the cause of this Throwable, or null if the cause does not exist or is unknown.
  5. getStackTrace(): Returns an array of StackTraceElements representing stack traces for this Throwable.

try-catch-finally

order of execution

  • When try does not catch an exception: the statements in the try block are executed one by one, and the program skips the catch block and executes the finally block and subsequent statements;

  • The case when try catches an exception and the exception is not handled in the catch statement block:

    • When a statement in a try block throws an exception, and there is no catch block to handle the exception, the exception will be thrown to the JVM, and the statements in the finally block will still be executed, but the statements after the finally block will not be executed;

    • When try catches an exception, there are cases to deal with this exception in the catch statement block: in the try statement block it is executed according to the order, when executing to a certain statement with an exception, the program will jump to the catch statement block, and match with the catch statement block one by one to find the corresponding handler, the other catch statement block will not be executed, and in the try statement block, the statements after an exception will not be executed. The statement after the exception will not be executed. After the catch block is executed, the statement in the finally block will be executed, and finally the statement after the finally block will be executed;

The execution flowchart is shown below:

Can also be used directly with try-finally, do not use catch, can be used in the code does not need to catch exceptions, you can ensure that the resource is closed after use. For example, IO stream after the execution of the corresponding operation, close the corresponding resources; the use of Lock object to ensure thread synchronization, through the finally can ensure that the lock will be released; database connection code, close the connection operation and so on.

Finally is not executed in the following cases:

  • () was used in the previous code to exit the program.

  • An exception occurred in the finally statement block.

  • The thread the program is in dies.

  • Shut down the CPU.

finally Classic Exception Handling Code Questions

Topic I

public class Test {
    public static void main(String[] args) {
        (test());
    }
    public static int test() {
        try {
            return 1;
        } catch (Exception e) {
            return 2;
        } finally {
            ("3");
        }
    }
}
//exports:
31

The basic usage of try, catch, and finally is that the finally block is executed before the return, so it outputs the 3 in finally and then the 1 in return, and since there is no exception in try, the return in catch is not executed.

Title II

public class Test {
    public static void main(String[] args) {
        (test());
    }
    public static int test() {
        try {
            int i = 1/0;
            return 1;
        } catch (Exception e) {
            return 2;
        } finally {
            ("3");
        }
    }
}
//exports:
32

The finally block is executed before the return, so it outputs the 3 from finally and then the 2 from the return in catch, and since there is an exception in try, the subsequent statements in try will not be executed.

Title III

public class Test {
    public static void main(String[] args) {
        (test());
    }
    public static int test() {
        try {
            return 2;
        } finally {
            return 3;
        }
    }
}
//exports:
3

The return in try is preceded by finally, and finally returns directly, so naturally you can't get to the return in try.

Title IV

public class Test {
    public static void main(String[] args) {
        (test());
    }
    public static int test() {
        int i = 0;
        try {
            i = 2;
            return i;
        } finally {
            i = 3;
        }
    }
}
//exports:
2

Before executing finally, the JVM will store the result of i, and then when finally finishes, it will return the stored result instead of i. So even though i has been changed to 3, the final result is still the stored result 2.

summarize

  1. Finally will definitely execute regardless of whether or not there is a return in the try and whether or not there is an exception.
  2. If an exception occurs in a try, the sentence in the catch is executed, and the statement at the location following the exception in the try is not executed.
  3. When there is a return statement in both the try and finally statements, the return in the try is ignored.
  4. In a try, there is a return, which stores the value temporarily, and no matter what is done with the value in the finally statement, the final return will be the value stored in the try statement.

try-with-resources Syntactic Sugar

contexts

Whenever there is a need to close the resource will be used to try-finally statement, for example, in the use of locks, whether local reentrant locks or distributed locks will be similar to the following structure of the code, will be in the final inside the unlock, used to force the unlock:

Lock lock = new ReentrantLock();
();
try {
    // doSometing
} finally {
    ();
}

Or when you read or write a file using java's file stream, you will also force the file stream to close in finally to prevent resource leakage.

InputStream inputStream = new FileInputStream("file");
try {
    ((new byte[4]));
} finally {
    ();
}

In fact, at first glance This should not be a problem, but if there are multiple resources need to close how should we write? The most common way is as follows:

InputStream inputStream = new FileInputStream("file");
OutputStream outStream = new FileOutputStream("file1");

try {
    ((new byte[4]));
    (new byte[4]);
} finally {
    ();
    ();
}

Where is the problem with defining two resources outside and then closing them in turn inside finally?

The problem is that if the exception is thrown at the time, then () will not be executed, which is obviously not the desired result, so it was changed to the following multi-nested way to write:

InputStream inputStream = new FileInputStream("file");
try {
    ((new byte[4]));
    try {
        OutputStream outStream = new FileOutputStream("file1");
        (new byte[4]);
    } finally {
        ();
    }
} finally {
    ();
}

In this way even though () throws an exception, it still executes to (), because they are in different finally blocks, this does solve the problem, but there are two other problems that are not solved:

  • If there are more than two resources, say ten, should I write ten nested statements? Will this code still look good after it's written?

  • If there is an exception in try and then another exception in finally, it will result in exception override, which will cause the exception in finally to override the exception in try.

public class CloseTest {

    public void close(){
        throw new RuntimeException("close");
    }

    public static void main(String[] args) {
        CloseTest closeTest = new CloseTest();
        try{
            throw new RuntimeException("doSomething");
        }finally {
            ();
        }
    }

}
//output result:Exception in thread "main" : close

In the above code, the expectation is that the doSomething exception will be thrown, but the actual data result is a close exception, which is not as expected.

How is try-with-resources solved?

Above introduced two problems, so in java7 introduced try-with-resources statement, as long as the resource implements the AutoCloseable interface that can use this statement, before the file stream has implemented this interface, so you can use directly:

try (InputStream inputStream = new FileInputStream("file"); 
    OutputStream outStream = new FileOutputStream("file1")) {
    ((new byte[4]));
    (new byte[4]);
}

All resource definitions are defined in parentheses after the try, and in this way several of the problems described above are solved:

  • By doing this, the code is very neat and clean, no matter how many resources there are.

  • The exception override problem can be seen experimentally by rewriting the code as follows:

public class CloseTest implements AutoCloseable {

    @Override
    public void close(){
        ("close");
        throw new RuntimeException("close");
    }

    public static void main(String[] args) {
        try(CloseTest closeTest = new CloseTest();
            CloseTest closeTest1 = new CloseTest();){
            throw new RuntimeException("Something");
        }
    }

}
//The output result is:
close
close
Exception in thread "main" : Something
    at (:33)
    Suppressed: : close
        at (:26)
        at (:34)
    Suppressed: : close
        at (:26)
        at (:34)

In the code, two CloseTests are defined to verify whether the previous close exception will affect the second one, and at the same time, different exceptions are thrown in both the close and try blocks, and you can see the result that two closes are output, which proves that both closes will be executed even though the close throws an exception. Then the doSomething exception is output, and you can see that the exception thrown in the try block is output here, and the exception of close is recorded as suppressed on the exception stack, so that both exceptions can be recorded in this way.

Exception Implementation Principle

The JVM's mechanism for handling exceptions

Exception Table, known as the Exception Table

try-catch

public static void simpleTryCatch() {
   try {
       testNPE();
   } catch (Exception e) {
       ();
   }
}

Use javap to analyze this code

//javap -c Main
public static void simpleTryCatch();
    Code:
       0: invokestatic  #3                  // Method testNPE:()V
       3: goto          11
       6: astore_0
       7: aload_0
       8: invokevirtual #5                  // Method java/lang/:()V
      11: return
    Exception table:
       from    to  target type
           0     3     6   Class java/lang/Exception

The Exception Table contains information about one or more Exception Handlers, which contain the following information

  • from the starting point of the possible anomaly

  • to End point of possible exception

  • target The location of the exception handler after an exception occurs before the above from and to.

  • type Information about the class of the exception handled by the exception handler.

When an exception occurs, the mechanism by which the JVM handles the exception is as follows:

  1. The JVM looks up the exception table in the method where the exception is currently occurring to see if there is an appropriate handler for the
  2. If the current method exception table is not empty and the exception matches the from and to nodes of the handler and the type also matches, the JVM calls the caller at target to handle it.
  3. If the previous entry does not find a reasonable handler, the search continues for the remaining entries in the exception table
  4. If the exception table for the current method cannot be handled, look up (pop the stack to handle) the call where the method was just invoked and repeat the above.
  5. If all stack frames are popped and still not processed, they are thrown to the current Thread and the Thread terminates.
  6. If the current Thread is the last non-guarded thread and an exception is not handled, it causes the JVM to terminate.

try-catch-finally

public static void simpleTryCatchFinally() {
   try {
       testNPE();
   } catch (Exception e) {
       ();
   } finally {
       ("Finally");
   }
}

Again, use javap to analyze the code

public static void simpleTryCatchFinally();
    Code.

      //try section.
      //If there is an exception, call the code at position 14, which is the catch part of the code.
      //If no exception occurs, the output finally operation is executed until goto at position 41, and the return operation is executed.

       0: invokestatic #3 // Method testNPE:()V
       3: getstatic #6 // Field java/lang/:Ljava/io/PrintStream.
       6: ldc #7 // String Finally
       8: invokevirtual #8 // Method java/io/:(Ljava/lang/String;)V
      11: goto 41

      // catch section:. If no exception occurs, the output finally operation is executed until the execution goto reaches position 41 and the return operation is executed.
      14: astore_0
      15: aload_0
      16: invokevirtual #5 // Method java/lang/:()V
      19: getstatic #6 // Field java/lang/:Ljava/io/PrintStream.
      22: ldc #7 // String Finally
      24: invokevirtual #8 // Method java/io/:(Ljava/lang/String;)V
      27: goto 41

      // If the code in the finally section is called, it is possible that an exception occurred in the try section or in the catch section.
      30: astore_1
      31: getstatic #6 // Field java/lang/:Ljava/io/PrintStream.
      34: ldc #7 // String Finally
      36: invokevirtual #8 // Method java/io/:(Ljava/lang/String;)V
      39: aload_1
      40: athrow // If the exception is not caught by a catch, but arrives here, it should still be thrown and passed to the caller after executing the finally statement.
      41: return
    Exception table.
       from to target type
           0 3 14 Class java/lang/Exception
           0 3 30 any
          14 19 30 any

The three exception tableitems above mean.

  • If, between 0 and 3, an exception of type Exception occurs, the exception handler at position 14 is called.

  • If between 0 and 3, whatever exception occurs, the handler at position 30 is invoked

  • If between 14 and 19 (i.e., the catch portion), the handler in position 30 is called regardless of what exception occurred.

In fact, the last two points mean that the finally block must be called with or without an exception

try-with-resources

The try-with-resources statement is actually a kind of syntactic sugar, and after compiling it goes back to the nested kind of pattern that you started talking about:

can be found try-with-resources was compiled, and then take the nested mode, but with the previous nesting is a little different, he closed the use of catch to catch the exception, and then added to the real exception, the overall logic is a little more complex than the previous nesting of our own.

abnormally long

The following test case simply tests a comparison of the time taken to create the object, create the exception object, and throw and catch the exception object:

public class ExceptionTest {
  
    private int testTimes;
  
    public ExceptionTest(int testTimes) {
         = testTimes;
    }  
  
    public void newObject() {
        long l = ();
        for (int i = 0; i < testTimes; i++) {
            new Object();
        }  
        ("Create an object:" + (() - l));
    }  
  
    public void newException() {
        long l = ();
        for (int i = 0; i < testTimes; i++) {
            new Exception();
        }  
        ("Creating Exception Objects:" + (() - l));
    }  
  
    public void catchException() {
        long l = ();
        for (int i = 0; i < testTimes; i++) {
            try {
                throw new Exception();
            } catch (Exception e) {
            }  
        }  
        ("build up、Throw and catch exception objects:" + (() - l));
    }  
  
    public static void main(String[] args) {
        ExceptionTest test = new ExceptionTest(10000);
        ();
        ();
        ();
    }  
}  

//in the end:
Create an object:575817
Creating Exception Objects:9589080
build up、Throw and catch exception objects:47394475

Creating an exception object takes about 20 times as long as creating a normal Object (in reality the difference is a bit bigger than that because loops also take up time; readers looking for precision can measure the time spent in an empty loop again and then subtract that before comparing), and throwing, catching, and catching an exception object takes about 4 times as long as creating an exception object.

About the Author.

From the front-line programmer Seven's exploration and practice, continuous learning iteration in the~

This article is included in my personal blog:https://

Public number: seven97, welcome to follow~