[Java Foundation] try, catch, finally

Keywords: Programming jvm Java

In this paper, try, catch, finally and return are combined by several examples.

Example 1:

	public String finallyTest() {
		String s = null;
		
		try {
			System.out.println("Enter try block");
			s = "try block";
			//String .valueOf(null);
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
		}

		return s;
	}

    System.out.println(finallyTest());


output: 

Enter try block
Enter finally block
finally block

Try, finally module will certainly enter, if an exception in try is caught by catch, it will be executed in the order of try, catch, finally. You can see that final will definitely be executed in the end, just like its name.

Example 2:

	public String finallyTest() {
		String s = null;
		
		try {
			System.out.println("Enter try block");
			s = "try block";
			String .valueOf(null);
			return s;
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
			return s;
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
		}

	}

    System.out.println(finallyTest());

output: 
Enter try block
Enter catch block
Enter finally block
catch block


//Decompiled as follows:
	public String finallyTest() {
		String s = null;

		String var4;//The final return is the variable, not the variable s you applied for!!!
		try {
			System.out.println("Enter try block");
			s = "try block";
			String.valueOf((char[]) null);
			var4 = s;
			return var4;
		} catch (Exception var7) {
			System.out.println("Enter catch block");
			s = "catch block";
			var4 = s;
		} finally {
			System.out.println("Enter finally block");
			s = "finally block";
		}

		return var4;
	}

Although the final module is executed, the return value is not changed. It can be seen from decompilation that the final return value is not the temporary variable s that we applied for, but the variable that jvm applied for itself, here is var4. Where there is a return, assign s to var4, and eventually return var4. So even if final is executed, the value of s changes, but the value of VAR4 does not.

But what if the return is a collection class, such as list, etc., will the modification in final affect the return value? The answer is yes, although the jvm will still apply for a temporary variable to store the list reference, and eventually return the reference pointed to by the temporary variable, final modifies the content of the reference pointed to heap memory, and eventually returns the reference to heap memory, so the modification in final will take effect. Interested students can try to revise it by themselves.

Example 3:

	@SuppressWarnings("finally")
	public String finallyTest() {
		String s = null;
		
		try {
			System.out.println("Enter try block");
			s = "try block";
			String .valueOf(null);
			return s;
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
			return s;
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
			return s;
		}

	}

    System.out.println(finallyTest());


outpu: 
Enter try block
Enter catch block
Enter finally block
finally block

//Decompiled as follows:
	public String finallyTest() {
		String s = null;

		try {
			System.out.println("Enter try block");
			s = "try block";
			String.valueOf((char[]) null);
		} catch (Exception var5) {
			System.out.println("Enter catch block");
			s = "catch block";
		} finally {
			;
		}
        
        //The return in try catch is ignored by jvm!!!

		System.out.println("Enter finally block");
		s = "finally block";
		return s;
	}

When there is return in final, the modification in final takes effect. Why? Example 2 mentions that when there is return in try and catch, the final return is the temporary variable of the jvm application, not s. Similarly, when there is return in final. And finally, it is certain that it will be executed, so the modification of temporary variables in try and catch will be overwritten in final, which means that there is no return. Looking at the decompilation results, jvm ignores all returns in try and catch.

Example 4:

What happens if catch doesn't catch exceptions in try?

	public String finallyTest() {
		String s = null;

		try {
			System.out.println("Enter try block");
			s = "try block";
			String .valueOf(null);
			return s;
		} catch (ArrayIndexOutOfBoundsException e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
			return s;
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
		}
	}

    System.out.println(finallyTest());

output: 
Exception in thread "main" Enter try block
Enter finally block
java.lang.NullPointerException
    ………

Obviously, ArrayIndexOutOfBoundsException did not catch an exception in try. Running this method would throw an exception without returning a value output. Although the catch does not catch the exception correctly, final will still execute. There is no return statement in final, so what happens if there is a return statement?

	public String finallyTest() {
		String s = null;

		try {
			System.out.println("Enter try block");
			s = "try block";
			String .valueOf(null);
			return s;
		} catch (ArrayIndexOutOfBoundsException e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
			return s;
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
			return s;
		}
	}

    System.out.println(finallyTest());

output:
Enter try block
Enter finally block
finally block

The previous example knows that an exception that catch does not capture should be thrown, but if there is a return statement in final, it will swallow the exception! Method callers assume that everything is okay and there is no error, at least from the final output. This violates the original intention of try, catch and finally, and fails to handle exceptions correctly.

Example 5:

In general, catch is to catch exceptions that may be thrown in try. What if catch itself throws exceptions when it processes them?

	public String finallyTest() {
		String s = null;

		try {
			System.out.println("Enter try block");
			s = "try block";
			String .valueOf(null);
			return s;
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
			String .valueOf(null);
			return s;
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
			//return s;
		}
	}

    System.out.println(finallyTest());

output:
Enter try block
Exception in thread "main" Enter catch block
Enter finally block
java.lang.NullPointerException
    …………

Exceptions thrown in try are caught by catch, and catch throws an exception, which can only be caught by the method caller. If not, an error will be reported.

There is no return statement in final in this example, and if the return statement is added, the exception will also be swallowed and not thrown, as in Example 4.

Example 6:

The possible exception thrown in try and catch is listed in the previous section, and final is bound to be executed. What if an exception is thrown in final?

	public String finallyTest() throws NullPointerException{
		String s = null;

		try {
			System.out.println("Enter try block");
			s = "try block";
			String .valueOf(null);
			return s;
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("Enter catch block");
			s = "catch block";
			String .valueOf(null);
			return s;
		}
		finally {
			System.out.println("Enter finally block");
			s = "finally block";
			int i = 1 / 0;
			return s;
		}
	}

    System.out.println(finallyTest());

outpu: 
Enter try block
Exception in thread "main" Enter catch block
Enter finally block
java.lang.ArithmeticException: / by zero
    ……

The final exception thrown is an exception in final, and the exception thrown in try and catch is swallowed up. If there is a return statement in final, the result is the same. It can be seen that if an exception is thrown in final, it can only be handled by the upper caller. This method itself is powerless.

The above examples basically cover a variety of scenarios. Now let's summarize:

1. When there is no return statement in final, if the return type is wrapper class, global variable, static variable (in short, non-stack storage type), the modification in final will affect the final return value. If not, it will not be affected. In try and catch, it will return the recently modified value.

2. When there is return statement in final, return in try and catch will be ignored, and if the exception in try is not caught correctly by catch or new exception is thrown by catch itself, final will be swallowed up, which is dangerous. Therefore, it is not recommended to add return statement in final.

3. finally will be executed, suitable for closing and releasing some resource files here, do not do some unnecessary operations to avoid throwing exceptions again.

 

Posted by sysera on Sun, 27 Jan 2019 08:51:14 -0800