Exception handling mechanism for Java

Source: Internet
Author: User
Tags finally block terminates throwable

Exceptions are a thing that everyone is "at arm's length" in everyday development, but virtually every high-level programming language has its own exception-handling mechanism, because no matter how powerful a programmer you are, it inevitably goes wrong, in other words: you're a good man and you have a Bug to write.

The so-called "exception handling mechanism" is the ability to return error messages as much as possible when you have a logic error, as well as the approximate location of the code where the error occurred, so you can troubleshoot the error.

At the same time, you do not have to think of the abnormal too advanced, it is just a false hint of information, but your program in the process of running some logic errors are checked out by the virtual machine, it encapsulates the error message and "Report" to you, and the specific how you deal with, depending on you.

Inheritance Architecture for exceptions

In Java, class Throwable is the highest parent of the entire exception handling mechanism, which has two subclasses of error and Exception, each representing "errors" and "exceptions."

And we always say that the exception is Exception, because the error is not controlled by our programmers, often due to internal problems caused by the virtual machine, such as: Insufficient memory leads to stack space overflow, virtual machine operation failure and so on.

In this case, the virtual machine terminates the direct thread and callbacks the error message via error and its subclass object. Therefore, we focus only on the anomalies of the Exception and its subclasses that can be controlled by us.

Our Exception anomalies are divided into two main categories, one is IOException (I/O input and output exception) and the other is RuntimeException (runtime exception). Among them, IOException and its subclasses are referred to as "",runtimeexception ", which is called" non-checked anomaly ".

The so-called anomaly refers to those exceptions that the compiler requires to be handled during compilation. For example: You write a piece of code to read and write files, and the compiler thinks that reading and writing files are likely to encounter a situation where the file does not exist, forcing you to write a code to deal with the file does not exist exception.

And the file here does not have an exception is a checked exception, you must be processed at the compile time.

Our runtimeexception is called a runtime exception because the compiler does not know what is wrong with your code, so it does not force you to handle the exception, wait until the runtime, if an exception occurs, the virtual opportunity callback error message.

Of course, if you pre-convict your code for an exception, you can capture it yourself, but then again, if you know a location that might be a problem, why don't you just give it a fix.

Therefore, the runtime exception is an unknown exception and does not force you to handle it.

Custom Exception Types

All exceptions defined in the Java exception mechanism cannot foresee all possible errors, and in some specific situations, we need to customize the exception type to report some error messages up.

Custom exception types are also fairly straightforward, and you can choose to inherit throwable,exception or their subclasses, and even you do not need to implement and override any method of the parent class to complete the definition of an exception type.

For example:

public class MyException extends RuntimeException{}
public class MyException extends Exception{}

Of course, if you want to provide more information for your exception, you can also rewrite multiple overloaded constructors, for example:

public class MyException extends RuntimeException{    public MyException(){}    public MyException(String mess){        super(mess);    }    public MyException(String mess,Throwable cause){        super(mess,cause);    }}

We know that any one of the exception types, whether in the Java API or our customizations, will inevitably inherit the Throwable class directly or indirectly.

And this Throwable class defines a String type of detailmessage field that stores the details of subclasses passing in about the subclass exception. For example:

public static void main(String[] args) {    throw new MyException("hello wrold failed");}

Output Result:

Exception in thread "main" test.exception.MyException: hello wrold failed    at test.exception.Test.main(Test.java:7)

Whenever the program encounters an exception, Java creates an object of the exception type as if it were a different object, stores it in the heap, and then the exception mechanism takes over the program, first retrieving whether the exception table of the current method can match the exception (the exception table holds all the exception sets that the current method has already handled).

If an exception is matched to an exception table, it jumps to the location of the bytecode that handles the exception, based on information about the exception handling stored in the exception table, to continue execution.

Otherwise, the virtual machine terminates the call of the current method and pops up the stack frame of the method, returning the method's call, and continuing to retrieve the caller's exception table to match the exception's handling.

If it does not match, eventually all the methods involved in the entire method call chain will bounce, not run properly, and the last virtual machine will print the error message for this exception.

This is a process in which the approximate exception arises to the end of the process, enough to show that if an exception is handled, then the program will be restored and able to continue execution, otherwise all methods involving the exception will be terminated.

As for the content of this exception, let's look at the specific implementation of the Printstacktrace method:

There is a total of three pieces of information, the first part consists of the name of the exception and its detailmessage, the second part is the exception of the call chain information, from the top down is the occurrence of the exception to the outer method of the call point, the third part is the source exception that caused the exception.

How exceptions are handled

About the handling of the exception, presumably everyone is most familiar with is Try-catch, Try-catch's basic syntax format is as follows:

try{    //你的程序}catch(xxxException e){    //异常处理代码}catch(xxxException e){    //异常处理代码}

The code in the try code block is also called the "Monitoring area",catch code block we call the exception handling area. " where each catch code block corresponds to an exception handling, the exception is saved in the method's exception table, and once any exception is generated in the try block, the exception handling mechanism retrieves from the exception table whether there is a block of code that handles the exception.

To be precise, the exception table holds the handled exception block that can only be used to process the code in our try block, and the same exception elsewhere will not be matched.

Of course, beyond that, we have a way of handling exceptions and throwing exceptions . For example:

public static void main(String[] args){    try{        calculate(22,0);    }catch (Exception e){        System.out.println("捕获一个异常");        e.printStackTrace();    }}public static void calculate(int x,int y){    if (y == 0)         throw new MyException("除数为 0");    int z = x/y;}

Output Result:

捕获一个异常test.exception.MyException: 除数为 0    at test.exception.Test_throw.calculate(Test_throw.java:14)    at test.exception.Test_throw.main(Test_throw.java:6)

We can use the Throw keyword to throw an exception manually, which is often the inability of the caller to handle an exception that needs to be left to the caller to handle.

Obviously, this way of throwing exceptions is meticulous, and requires a programmer to have a certain pre-judgment, Java has another way to throw an exception, see:

public static void calculate2(int x,int y) throws ArithmeticException{    int z = x/y;}

This way compared to "rough", I do not care where you will be abnormal, as long as you encounter arithmeticexception type of exception, you throw it out for me.

In fact, the second is essentially the same as the first, when the virtual machine in the X/Y, when found that y equals zero, will also be new to a ArithmeticException object, and then the program to the exception mechanism.

But the latter is more convenient than the former, do not care which location you will be abnormal, do not need to make a manual judgment, everything to the virtual machine good. But the obvious disadvantage is that the control of the exception is not in its own hands, some of the custom exception virtual machine can not be judged when running.

For example, if our Calculate2 method here does not allow Y equals 1, if it equals 1, throw a myexception exception. In this case, the latter can not be achieved, because the divisor is 1 in the virtual machine there is no problem at all, you call it how to throw an exception. It is simply a matter of using the former to throw an exception manually.

However, you have to be clear that whether you use throw to throw an exception manually, or use throws to let the virtual machine throw an exception for us dynamically, you always need to handle the exception in a certain location, which needs to be clarified.

Not to say your trash you do not want to clean up, you throw to your front table classmate, your front table also do not want to clean up, has been thrown forward, but the front of the person always have to deal with it, otherwise you will wait for your class teacher to clean up and then pack you up.

try-catch-finally Order of execution

The questions related to the order of execution of try-catch-finally can be described as "regulars" in various interviews, especially in the case of the finally block with a return statement. We look directly at several interview questions:

Interview Question one:

public static void main(String[] args){    int result = test1();    System.out.println(result);}public static int test1(){    int i = 1;    try{        i++;        System.out.println("try block, i = "+i);    }catch(Exception e){        i--;        System.out.println("catch block i = "+i);    }finally{        i = 10;        System.out.println("finally block i = "+i);    }    return i;}

Let's figure out what the programmer will end up running.

The output results are as follows:

try block, i = 2finally block i = 1010

This is a fairly simple question, no pits, let's change a little bit:

public static int test2(){    int i = 1;    try{        i++;        throw new Exception();    }catch(Exception e){        i--;        System.out.println("catch block i = "+i);    }finally{        i = 10;        System.out.println("finally block i = "+i);    }    return i;}

The output results are as follows:

catch block i = 1finally block i = 1010

The result of the operation must be expected, the program throws an exception and is then captured and processed by the catch block of this method.

Interview question two:

public static void main(String[] args){    int result = test3();    System.out.println(result);}public static int test3(){    //try 语句块中有 return 语句时的整体执行顺序    int i = 1;    try{        i++;        System.out.println("try block, i = "+i);        return i;    }catch(Exception e){        i ++;        System.out.println("catch block i = "+i);        return i;    }finally{        i = 10;        System.out.println("finally block i = "+i);    }}

The output results are as follows:

try block, i = 2finally block i = 102

Is it a little confusing? Clearly I have a return statement in the TRY statement block, but why did the code in the finally block finally execute?

We decompile this class and look at the implementation of this test3 method's compiled byte code:

0:iconst_1//load 1 into the operand stack 1:istore_0//store The elements of the operand stack 0 in the local variable table 2:iinc 0, 1//Add an element directly to the local variable table 0 position (i= 2) println method 5:getstatic #3//5-27 rows 8:new #5 11:dup12:invokespe                                                     cial #6 15:ldc #7 17:invokevirtual #8                                                     20:iload_0 21:invokevirtual #9 24:invokevirtual #10 27:invokevirtual #11 30:iload_0//loading the elements of the local variable table 0 position into the Operation Stack (2  ) 31:istore_1//Put the element at the top of the Operation Stack in the local variable table position 1 32:bipush 10//load a constant to the Operation Stack (TEN) 34:istore_0//Add 10 to the local variable table 0 at 35: Getstatic #3//35-57 Line executes the println method in finally 38:new #5 41:dup42:invokespeci Al #6 45:ldc #12 47:invokevirtual #8 50:iload_051:invokevi                Rtual #954:invokevirtual #10 57:invokevirtual #11 60:iload_1//loading the elements of the local variable table 1 position into the Operation Stack (2) 6  1:ireturn//Returns the top element of the action stack (2)-------------------try + finally end------------------------------below is the catch + Finally, similar ------------62:astore_163:iinc 0, 1 ........

As can be seen from our analysis, the contents of the finally code block are always executed, regardless of whether the program is an exception, the compiler copies the code in the finally block by two copies and adds them after the try and catch, respectively.

Some people may wonder, originally our I was stored in the local variable table 0 position, and finally the code in the final finally the slot 0 is filled with the value 10, why the last program still return the value of 2?

Looking closely at the bytecode, you will find that the virtual opportunity will press the return value into the operand stack until the return statement is returned, and wait for it to return, even if the finally statement block modifies I, but the value to be returned already exists in the operand stack, so it does not affect the program's return result.

Interview question three:

public static int test4(){    //finally 语句块中有 return 语句    int i = 1;    try{        i++;        System.out.println("try block, i = "+i);        return i;    }catch(Exception e){        i++;        System.out.println("catch block i = "+i);        return i;    }finally{        i++;        System.out.println("finally block i = "+i);        return i;    }}

Operation Result:

try block, i = 2finally block i = 33

In fact, you look at the whole process from its bytecode instructions, not just four of its execution process.

You will find that the program will eventually return with a return statement in the finally code block, ignoring the return instruction in the TRY statement block directly.

Finally, there is an unwritten convention for the use of exceptions: try to do the same in a centralized location, do not use try-catch everywhere, or it will make the code structure chaotic .

All the code, pictures, and files in the article are stored on my GitHub:

(Https://github.com/SingleYam/overview_java)

Welcome to the public number: in the code of the high-base, all the articles will be synchronized in the public number.

Exception handling mechanism for Java

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.