“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Final, finally, Finalize

Interview research site

Objective: To understand the basic knowledge of Java.

Scope: Java programmers with 1-3 years of experience.

Background knowledge

Final /finally is used almost all the time at work, so even without a systematic comb of this question, you can answer something.

However, Finalize has very little contact with us. Next, we will analyze these keywords one by one.

The final keyword

The final keyword stands for immutability.

In the interview questions series: 5 years of work, the first time so sober understanding of the final keywords? In this article, I have carried out a detailed analysis, I suggest that you go to see this article, here will not repeat the analysis.

Finally the keyword

The finally keyword is used after a try block. The usual form is finally

try{}catch(){
  
}finally{}Copy the code

And the following form.

try{}finally{}Copy the code

The code ina finally block must be executed regardless of whether there is an exception ina try or catch block, so it is usually used for cleanup, closing links, and so on.

Its features:

  1. finallyStatements are bound to accompanytryStatement appears.
  2. tryStatements cannot be used alone; they must be used togethercatchStatements orfinallyStatements.
  3. tryStatements can be separate fromcatchStatement, or can be used alonefinallyStatement, or all three.

Finally, practical thinking

To help you understand the finally keyword, let’s look at this code.

So let’s think about this: what are the results of this code?

public class FinallyExample {
    
    public static void main(String arg[]){
        System.out.println(getNumber(0));
        System.out.println(getNumber(1));
        System.out.println(getNumber(2));
        System.out.println(getNumber(4));
    }
    public static int getNumber(int num){
        try{
            int result=2/num;
            return result;
        }catch(Exception exception){
            return 0;
        }finally{
            if(num==0) {return -1;
            }
            if(num==1) {return 1; }}}}Copy the code

The correct answers are:

  1. - 1Introduced:num=0, an error is reportedjava.lang.ArithmeticException: / by zero. So intocatchCatch the exception. Due to thefinallyThe statement block must be executed, so enterfinallyStatement block, return- 1.
  2. 1Introduced:num=1, the program is running normally becausefinallyThe statement block must be executed, so enterfinallyCode block, get the result1.
  3. 1Introduced:num=2, the program is running normally.result=1Because offinallyThe statement block must be executed, so enterfinallyCode block, butfinallyThe statement block does not trigger changes to the result, so the result is returned1.
  4. 0Introduced:num=4, the program is running normally.result=0Since 2/4=0.5, the conversion to int yields 0finallyThe statement block must be executed, so enterfinallyCode block, butfinallyThe statement block does not trigger changes to the result, so the result is returned0.

Under what circumstancesfinallyDo not perform

Is there a situation where finally blocks will not be executed?

System.exit()

Take a look at this code:

public class FinallyExample {

    public static void main(String arg[]){
        System.out.println(getNumber(0));
    }
    public static int getNumber(int num){
        try{
            int result=2/num;
            return result;
        }catch(Exception exception){
            System.out.println("Trigger exception execution");
            System.exit(0);
            return 0;
        }finally{
            System.out.println("Execute a finally block"); }}}Copy the code

Add system.exit (0) code to the catch block, and the result is as follows

Trigger exception executionCopy the code

You can see that the finally block is not executed in this case.

To expand, why does system.exit (0) break finally?

Take a look at the source code and comments.

/**
     * Terminates the currently running Java Virtual Machine. The
     * argument serves as a status code; by convention, a nonzero status
     * code indicates abnormal termination.
     * <p>
     * This method calls the <code>exit</code> method in class
     * <code>Runtime</code>. This method never returns normally.
     * <p>
     * The call <code>System.exit(n)</code> is effectively equivalent to
     * the call:
     * <blockquote><pre>
     * Runtime.getRuntime().exit(n)
     * </pre></blockquote>
     *
     * @param      status   exit status.
     * @throws  SecurityException
     *        if a security manager exists and its <code>checkExit</code>
     *        method doesn't allow exit with the specified status.
     * @see        java.lang.Runtime#exit(int)
     */
public static void exit(int status) {
  Runtime.getRuntime().exit(status);
}
Copy the code

This method is used to terminate the currently running Java JVM. If status is a non-zero parameter, it indicates an abnormal exit.

  1. System.exit(0) : Close all contents of the entire virtual machine and free all memory! Exit the program normally.

  2. System.exit(1) : Exit the program abnormally

  3. System.exit(-1) : Exit the program abnormally

Because the current JVM has ended, the program code naturally cannot continue to execute.

The daemon thread is interrupted

Let’s start with the following code:

public class FinallyExample {

    public static void main(String[] args) {
        Thread t = new Thread(new Task());
        t.setDaemon(true); // make it a daemon thread
        t.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException("the "+Thread.currentThread().getName()+" has been interrupted",e); }}}class Task implements Runnable {
    @Override
    public void run(a) {
        System.out.println("Execute the run() method");
        try {
            System.out.println("Execute the try block");
            TimeUnit.SECONDS.sleep(5); 5 s / / jam
        } catch(InterruptedException e) {
            System.out.println("Execute a catch block");
            throw new RuntimeException("the "+Thread.currentThread().getName()+" has been interrupted",e);
        } finally {
            System.out.println("Execute a finally block"); }}}Copy the code

The running results are as follows:

Execute the run() method executiontryblockCopy the code

It turns out that the code in the finally statement block was not executed? Why is that?

The property of daemon threads is that as long as there are no non-daemon threads running in the JVM, the virtual machine kills all daemon threads to terminate the program. In other words, whether the daemon thread is running or not does not affect the termination of the JVM.

In a virtual machine, the garbage collector thread and the main thread are both daemon threads.

In the program run above, the execution logic is described as follows:

  1. threadtIs a daemon thread that starts a taskTaskExecute, the threadtinmainMethod, and after sleeping for 1s,mainMethod execution end
  2. TaskIs the execution task of a daemon thread that sleeps 5s.

Due to the nature of daemons, both main and Task are daemons, so when the main thread finishes execution, it does not block because the task has not finished execution. Instead, the process is terminated after waiting for 1s.

This leaves the Task thread code unfinished, but the JVM process has ended, so the finally block is not executed.

Finally Execution order

Based on the above understanding, do you think you have a good command of finally keyword? So let’s look at the following problem.

What is the result of executing this code?

public class FinallyExample2 {

  public int add(a) {
    int x = 1;
    try {
      return ++x;
    } catch (Exception e) {
      System.out.println("Execute a catch block");
      ++x;
    } finally {
      System.out.println("Execute a finally block");
      ++x;
    }
    return x;
  }
  public static void main(String[] args) {
    FinallyExample2 t = new FinallyExample2();
    inty = t.add(); System.out.println(y); }}Copy the code

The results of the above program are: 2

This should come as a surprise because, in finally semantics, the first try block executed with ++x should yield 2. Then the finally block executed with +1 should yield 3. Why 2?

Before answering this question, take a look at the bytecode for this code, using Javap -v FinallyExample2.

 public int add(a);
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_1     // The iconst directive pushes constants onto the stack.
         1: istore_1     //
         2: iinc          1.1  // Perform the ++x operation
         5: iload_1       
         6: istore_2
         7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        10: ldc           #3                  // String Executes the finally statement block
        12: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;) V
        15: iinc          1.1
        18: iload_2
        19: ireturn
        20: astore_2
        21: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        24: ldc           #6                  // String executes the catch block
        26: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;) V
        29: iinc          1.1
        32: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        35: ldc           #3                  // String Executes the finally statement block
        37: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;) V
        40: iinc          1.1
        43: goto          60
        46: astore_3
        47: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        50: ldc           #3                  // String Executes the finally statement block
        52: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;) V
        55: iinc          1.1
        58: aload_3
        59: athrow
        60: iload_1
        61: ireturn
      Exception table:
         from    to  target type
             2     7    20   Class java/lang/Exception
             2     7    46   any
            20    32    46   any
Copy the code

A brief description of the byte instructions relevant to this case study

  • iconstAnd push the constant onto the stack.
  • istore, the int value at the top of the stack is stored in the local variable table.
  • iloadPush a variable of type int to the top of the stack.
  • iinc, add n to the element whose index is I in the table of local variables.
  • ireturn, returns a value of type int.
  • astoreTo store a value from the operand stack to the local variable table.
  • athrowThrows an exception.
  • aloadTo load a local variable onto the operation stack.

With these instructions in mind, it’s time to analyze the bytecode content above.

Let’s start with the first step, which is the instruction in the try block.

0: iconst_1     // The iconst directive pushes constants onto the stack.
1: istore_1     //
2: iinc          1.1  // Perform the ++x operation
5: iload_1       
6: istore_2
Copy the code

The execution process of the above instructions is illustrated below.

Moving on to the bytecode, this is the instruction executed in finally.

15: iinc          1.1
18: iload_2
19: ireturn
20: astore_2
Copy the code

As you can see from the diagram above, the finally statement adds up the value of x, but eventually returns 2.

The remaining instructions are the execution instructions corresponding to the exception table. The interpretation of the exception table is as follows:

  • From lines 2 to 7, if an Exception is raised, the instruction jumps to line 20 to begin execution.

  • From lines 2 to 7, if any exceptions are raised, the execution jumps to line 46.

  • From lines 20 to 32, if any exceptions are raised, the execution jumps to line 46.

Exception table:
  from    to  target type
    2     7    20   Class java/lang/Exception
    2     7    46   any
    20    32    46   any
Copy the code

Conclusion: It can be seen from the above byte instruction execution process that when there is a return in the try, the code before the return will be executed first, then the information that needs to return will be temporarily saved, then the code in Finally will be executed, and finally the saved information will be returned by return. So the result of this run is 2, not 3.

In addition, there are other variations, such as:

public class FinallyExample2 {

    public int add(a) {
        int x = 1;
        try {
            return ++x;
        } catch (Exception e) {
            System.out.println("Execute a catch block");
            ++x;
        } finally {
            System.out.println("Execute a finally block");
            ++x;
            returnx; }}public static void main(String[] args) {
        FinallyExample2 t = new FinallyExample2();
        inty = t.add(); System.out.println(y); }}Copy the code

So, what is the result of this code run?

The print result is as follows:

Execute the finally block 3Copy the code

Conclusion: A return ina try is invalid when finally has a return in it. After a finally return is executed, the return in the try is never executed again. However, it is not recommended to write a return in finally. This undermines the integrity of the program, and an exception in finally can cause the exception ina catch to be overwritten.

Exceptions and finally are explained in the JVM for this section.

If the try clause executes a return, the compiled code does the following:

  1. Saves the return value (if any) in a local variable.
  2. Executes a jsr to the code for the finally clause.
  3. Upon return from the finally clause, returns the value saved in the local variable.

A simple translation is as follows:

If a try statement contains a return, the code behaves like this:

  1. If there is a return value, it is saved to a local variable
  2. Execute JSR to finally statement
  3. After the finally statement is executed, return the value previously saved in the local variable list

The finalize method

Finalize method is defined in Object class, and its method definition is as follows:

protected void finalize(a) throws Throwable {}Copy the code

This method may be called when a class is being recycled.

It has rules of use:

  1. When an object is no longer referenced by any object, the GC calls the Finalize () method of that object
  2. Finalize () is an Object method, and subclasses can override this method to do some system resource release or data cleanup
  3. The object can be referenced again in Finalize () to avoid GC collection; But the most common purpose is to do cleanup
  4. Java does not guarantee that Finalize () will be executed; But make sure that the thread calling Finalize does not hold any User-Visible synchronization lock.
  5. Exceptions thrown in Finalize will be ignored and the method will terminate.
  6. When Finalize is called, the JVM checks again to see if the object can be accessed by a living thread. If not, the object will be cleared. Finalize can only be called once; That is, it takes two GC cycles for objects overriding the Finalize method to be cleared.

I want to answer

Final, finally, Finalize

Answer:

  1. Final modifies classes, methods, and properties. A class modified by final cannot be inherited, a property modified by final cannot be modified, and a method modified by final cannot be overridden

  2. Finally, which, along with the try block, forms a complete syntax for a block of code that must be executed, and there are ways to break its execution nature

    1. Through the System. The exit
    2. Termination of the daemon thread
  3. Finalize method is a method that can be called when a class is being recycled.

The problem summary

An interview question, to be dug down, can produce many variations.

This article may not cover all possible scenarios, but readers must note that only systematic knowledge can create value

This article is from the original work of “Follow Mic Architecture”. If you need to reprint, please pay attention to the author’s public account with the same name.