在try catch块以及finally中return的位置直接影响程序执行的结果,我以返回值的类型和return出现的位置分类对各个情况的执行结果进行说明。
先上结论:

  1. 当返回类型为基本数据类型时:
    (1) finally中没有return,返回值就是return处的值。eg:
public static void main(String[] args) {
                        System.out.println(testPrimitive());           
        } 
        
         public static int testPrimitive() {
		        int x = 0;
		        try {
		            x = 1;
		            return x;
		        } catch (Exception e) {
		            x = 2;
		            return x;
		        } finally {
		            x = 3;          //基本类型的返回值,不可被修改
		         //   return x;    //可以被“具体值”覆盖
		        }     }
输出 1

可能有人会想说finally下面有return呢?其实finally下面有return的作用等效于在try块里面和catch块里面加上return,作用是一样的,把try块里面的return和catch里面的return注释掉,然后在finally外面加上return,是一回事。所以,finally外面有return,结果还是1.

原因:之所以出现这种原因经过查看class文件(可以通过dos命令查看class文件: javap -verbose className或者javap - c className) 可以了解在try的return之后会将x变量的值赋给新的变量x’,然后最终将x’返回,所以fianlly怎么操作x都不影响x‘的值。

java 中 return 的性能和 if 的性能 java return和finally_System

(2) finally中有return,首先要说明,正常是不建议在finally块里面写return语句的,原因就是因为
a: 可能会覆盖正常的流程返回的值造成代码难以理解,
b:如果finally块中包含了return语句,如果try块中抛出异常即使在catch块重新抛出了异常,则调用该方法的语句也不会获得catch块重新抛出的异常,由于最终会执行finally块,如果在finally中有返回return,n那会得到finally块的返回值,并且不会捕获异常。异常就被“吃”掉了。

但是如果写了,正常也是可以编译过不报错的,所以这里进行一下具体的分析:
eg:

public static void main(String[] args) {
 
System.out.println(test());;
}

    static int test()
{
	int x = 2;
	try
	{
		x++;
	  // int	i =  1/0;
		return x;
	}catch(Exception e){
		x++;
		// int	i =  1/0;
		return x;
	}finally
{

	//try {
	//	int i = 1/0;
	
	++x;
	return x;
}
}

输出 3.

原因

java 中 return 的性能和 if 的性能 java return和finally_字节码_02


这里给出一个示例,通过查看calss字节码文件可知,在执行try块的时候在返回之前直接goto到了finally,try块中的return x并没有执行到。返回的仍旧是变量x.

以上是基本类型的,那接下来再看看引用类型的。

(1)finally中没有return

public static void main(String[] args) {
        System.out.println(test());
        //System.out.println(testPrimitive());
    }
 
public static Student test() {  //对象的地址值没有变
    Student result = new Student("Tom", 0);
    try {
        result.setAge(1);
        return result;
    } catch (Exception e) {
        result.setAge(2);
        return result;
    } finally {
        result.setAge(3);       //引用类型的返回值,可被修改
        //return new Student("Kobe", 33);   //可以被“具体值”覆盖
    }
  //  return new Student("Kobe", 33); 
}
输出:Tom 3

原因:这个很容易理解,因为java中应用类型时址传递,因此finally中其实是对new Student(“Tom”, 0);这个对象的地址操作,看字节码:

java 中 return 的性能和 if 的性能 java return和finally_retrun_03


(2)finally中有return

public static Student test() {  //对象的地址值没有变
		        Student result = new Student("Tom", 0);
		        try {
		            result.setAge(1);
		            return result;
		        } catch (Exception e) {
		            result.setAge(2);
		            return result;
		        } finally {
		           // result.setAge(3);       //引用类型的返回值,可被修改
		         //  return result;
		            return new Student("Kobe", 33);   //可以被“具体值”覆盖
		        }
		      //  return new Student("Kobe", 33); 
		    }

同样字节码中同样goto了,看图:

java 中 return 的性能和 if 的性能 java return和finally_java_04


所以这里最后输出Kobe 33

再贴一个例子大家看看:

public static void main(String[] args) {
	    System.out.println(getMap().get("KEY").toString());
	}
 
public static Map<String, String> getMap() {
    Map<String, String> map = new HashMap<String, String>();
    map.put("KEY", "INIT");
     
    try {
        map.put("KEY", "TRY");
       // System.out.println(map + "111111");
        return map;
    }
    catch (Exception e) {
        map.put("KEY", "CATCH");
        return map;
    }
    finally {
        map.put("KEY", "FINALLY");
    	// System.out.println(map + "222222");
        map = null;
       // System.out.println(map + "333333");
      //  return map;
    }
   // System.out.println(map + "444444");
   // return map;
}

刚开始我一直以为会是空指针,因为按照字节码在try块的return处拷贝了一个变量出来,但是在finally处已经将map这个对象置空了,所以应该拷贝的对象也是空,但是最后输出结果是FINALLY后来发现自己一直有一个知识点错误:
看下例:

public static void main(String[] args) {
       // System.out.println(test());
        //System.out.println(testPrimitive());
		Student result = new Student("Tom", 0);
		System.out.println(result);
		Student s = result;
		//s.setAge(20);
		//result.setName("Jerry");
		System.out.println(s);
		result = null;
		//s.setAge(10);
		System.out.println("--------------");
		System.out.println(result);
		System.out.println(s);
    }
    看输出:
    com.csdn.ReturnAndFinallyTest$Student@179935d
    com.csdn.ReturnAndFinallyTest$Student@179935d
    --------------
    null
    com.csdn.ReturnAndFinallyTest$Student@179935d

我最初以为result置空之后s应该也是空,但是实际情况是s还是指向的是原对象,所以Student s = result;可以理解为将new Student(“Tom”, 0);这个对象再增加一个引用,s也指向这个对象,当result为nul时,s仍然不变。
类似的错误还有:

Clazz c1 = new Clazz();
c1.setP1("123);
System.out.println(c1.getP1()); //输出123
method(c1);
System.out.println(c1.getP1());//还是输出123,因为method方法中的c1是局部变量,方法执行完就弹栈了。如果没有c1 = new Clazz(); 那这里输出的就是234
  void  method(Clazz c1){
       c1 = new Clazz();
       c1.setP1("234");
 
};

以上。