`

return和finally的执行顺序问题

    博客分类:
  • Java
 
阅读更多

一、引言

      当try里面有return,finally里面也有return时会有怎么的结果呢?

二、代码 

      话不多说,直接用代码进行测试。测试代码如下,

public class FinallyTest {
	
private static final FinallyTest instance = new FinallyTest("instance");
	
         /**
	 * @param value
	 */
	private FinallyTest(String value) {
		super();
		this.value = value;
	}

	private String value;

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	/**
	 * <p>测试基本类型
	 * @return
	 */
	public int testReturnInt() {
		int b = 60;
		try {
			System.out.println("testReturnInt() in try. b = " + b);
//			throw new NullPointerException();
			 return b += 50;
		} catch (Exception e) {
			System.out.println("testReturnInt() in catch. b = " + b);
//			return b +=100;
		}finally {
			System.out.println("finally before edit. b = " +b);
			b = 2000;
			System.out.println("finally after edit. b= " + b);
		    return b;
		}
//		System.out.println("out of finally");
//		return b + 1000;
	}

	/**
	 * <p>测试对象 
	 * @return
	 */
	public FinallyTest testReturnObj() {
		FinallyTest demo = new FinallyTest("origin");
		try {
			System.out.println("testReturnObj() in try. value = " + demo.getValue());
			return demo;
		} catch (Exception e) {
			System.out.println("testReturnObj() in catch. value = " + demo.getValue());
		} finally {
			System.out.println("finally before edit. value = " + demo.getValue());
			demo.setValue("modified");
			System.out.println("finally after edit. value = " + demo.getValue());
		    return demo;
		}
//		System.out.println("out of finally");
//		return demo;
	}

	public static void main(String[] args) {
		System.out.println("in main. int =" + instance.testReturnInt()+"\n*************");
		System.out.println("in main. value = " + instance.testReturnObj().getValue());
	}	  

}

    注意:上面这种return的方式(即在finally里面加上return),在eclipse里面会出现"finally block does not complete normally"的警告,下文会对此作一个说明。这里因为要举例,仍然暂时这么写。

 

三、测试用例

   把try,catch,finally的情况分为三种:

   1.try和finally型(即上文中的代码):

try{
  return a = xxx;
}catch(Exception e){
  xxx
}finally{
  return a = xxxx;
}
   终端输出:
testReturnInt() in try. b = 60
finally before edit. b = 110
finally after edit. b= 2000
in main. int =2000
*************
testReturnObj() in try. value = origin
finally before edit. value = origin
finally after edit. value = modified
in main. value = modified
   结论:不论是基本类型还是引用对象,finally里面的return都会覆盖try里的return,这种方式不推荐。
    2.catch和finally型:
try{
  xxx;
}catch(Exception e){
  return a = xxx;
}finally{
  return a = xxxx;
}

   相应地把testReturnInt()和testReturnObj()的return移动到catch里面,其他不变:

	/**
	 * <p>测试基本类型
	 * @return
	 */
	public int testReturnInt() {
		int b = 60;
		try {
			System.out.println("testReturnInt() in try. b = " + b);
//			throw new NullPointerException();
//			 return b += 50;
//			return b+50;
		} catch (Exception e) {
			System.out.println("testReturnInt() in catch. b = " + b);
			return b +=50;
		}finally {
			System.out.println("finally before edit. b = " +b);
			b = 2000;
			System.out.println("finally after edit. b= " + b);
		    return b;
		}
//		System.out.println("out of finally");
//		return b + 1000;
	}

	/**
	 * <p>测试对象 
	 * @return
	 */
	public FinallyTest testReturnObj() {
		FinallyTest demo = new FinallyTest("origin");
		try {
			System.out.println("testReturnObj() in try. value = " + demo.getValue());
//			throw new NullPointerException();
//			return demo;
		} catch (Exception e) {
			System.out.println("testReturnObj() in catch. value = " + demo.getValue());
			return demo;
		} finally {
			System.out.println("finally before edit. value = " + demo.getValue());
			demo.setValue("modified");
			System.out.println("finally after edit. value = " + demo.getValue());
		    return demo;
		}
//		System.out.println("out of finally");
//		return demo;
	}
    终端输出:
testReturnInt() in try. b = 60
finally before edit. b = 60
finally after edit. b= 2000
in main. int =2000
*************
testReturnObj() in try. value = origin
finally before edit. value = origin
finally after edit. value = modified
in main. value = modified
     可以看到,由于没有异常,所以不会走catch分支,因此基本类型的值在finally before edit处不变,而引用对象的值由于是在finally里中set,因此仍然发生了变化。
    如果把try中throw new NullPointerException();这句话的注释去掉,从而走catch分支,那么输出结果就和情况1是一样的。即基本类型的值在finally before edit处发生变化。
   但从最终结果来看:不论是否发生异常,finally里面的return都是最终返回的值,即都会覆盖catch中的return。

   3.try,catch,finally型

try{
  xxx;
  return a = xxx;
}catch(Exception e){
  return a = xxx;
}finally{
  return a = xxxx;
}

   修改testReturnInt()和testReturnObj()如下:,通过传入不同的参数来决定是否走catch分支:

	/**
	 * <p>
	 * 测试基本类型
	 * 
	 * @return
	 */
	public int testReturnInt(int i) {
		int b = 60;
		try {
			System.out.println("testReturnInt() in try. b = " + b);
			if (i == -1) {
				throw new NullPointerException();
			} else {
				return b += 50;
			}
			// return b+50;
		} catch (Exception e) {
			System.out.println("testReturnInt() in catch. b = " + b);
			return b += 50;
		} finally {
			System.out.println("finally before edit. b = " + b);
			b = 2000;
			System.out.println("finally after edit. b= " + b);
			return b;
		}
		// System.out.println("out of finally");
		// return b + 1000;
	}

   这里基本上是对上述情况1和情况2的结合。不再给出具体的终端输出,结论仍然和情况1和情况2类似,即fianlly里面的return会对前面的return(不论是try还是catch分支进行覆盖)。

  

  四、细心的同学应该会发现,其实我们还少了一种情况: 

  

try{
xxx;
return a = xxx;
}catch(Exception e){
a=xxx;
}finally{
xxx;
a = xxxx;
}
System.out.println("out of finally");
a=xxx;
return a;
    代码修改如下:

 

 

	/**
	 * <p>
	 * 测试基本类型
	 * 
	 * @return
	 */
	public int testReturnInt(int i) {
		int b = 60;
		try {
			System.out.println("testReturnInt() in try. b = " + b);
			if (i == -1) {
				throw new NullPointerException();
			}
			return b += 50;
		} catch (Exception e) {
			System.out.println("testReturnInt() in catch. b = " + b);
			// return b += 50;
		} finally {
			System.out.println("finally before edit. b = " + b);
			b = 2000;
			System.out.println("finally after edit. b= " + b);
			// return b;
		}
		System.out.println("out of finally");
		return b;
	}

	/**
	 * <p>
	 * 测试对象
	 * 
	 * @return
	 */
	public FinallyTest testReturnObj(Object object) {
		FinallyTest demo = new FinallyTest("origin");
		try {
			System.out.println("testReturnObj() in try. value = "
					+ demo.getValue());
			if (object == null) {
				throw new NullPointerException();
			} 
			return demo;
		} catch (Exception e) {
			System.out.println("testReturnObj() in catch. value = "
					+ demo.getValue());
			// return demo;
		} finally {
			System.out.println("finally before edit. value = "
					+ demo.getValue());
			demo.setValue("modified");
			System.out
					.println("finally after edit. value = " + demo.getValue());
			// return demo;
		}
		System.out.println("out of finally");
		demo.setValue("out of finally");
		return demo;
	}

	public static void main(String[] args) {
		System.out.println("in main. int =" + instance.testReturnInt(0)
				+ "\n*************");
		System.out.println("in main. value = "
				+ instance.testReturnObj(new Object()).getValue());
	}
    终端输出:

 

 

testReturnInt() in try. b = 60
finally before edit. b = 110
finally after edit. b= 2000
in main. int =110
*************
testReturnObj() in try. value = origin
finally before edit. value = origin
finally after edit. value = modified
in main. value = modified
     正常情况下会执行try中的return,finally中的代码也会执行,但是finally外面的代码不会执行。另外值得注意的是基本类别的值在finally中发生了变化(对应输出中的:finally after edit. b= 2000),但是最终返回到main中的值仍然是try中的return即finally中的对基本类类型的修改是无效的(即对调用方是无效的);然而finally中对引用对象的修改却是有效的。

 

 

       出现异常时会执行finally外面的return。这里不再作截图,读者有兴趣可以自行测试。

       可见这种情况下a的值最多有可能在四个地方被改变,程序极易出现混乱,可读性很差,因此极其不推荐。

 

 

四、结论

     终上,finally有return时,finally里面的return会覆盖原来的数据,而且也会修改原来的对象引用(基本类型数据不变----除非在finally之后有return语句)。所以,为了避免混乱,建议不要在finally里面写return。一般采用如下形式:

try{
xxx;
a=xxx;
return a;
}catch(Exception e){
xxx;
a=xxx;
return a;
}finally{
 xxx;
}

   或者统一在最后作return

 

try{
xxx;
a=xxx;
}catch(Exception e){
xxx;
a=xxx;
}finally{
 xxx;
}
return a;
    即finally里面不要作return(如非必要也尽量不要对返回的数据作修改),只作一些必要的关闭资源的工作。
分享到:
评论

相关推荐

    try、catch、finally、return 执行顺序.doc

    下面我们来详细讲解 try、catch、finally、return 执行顺序的规则和特点。 首先,我们需要了解 try、catch、finally 语句的基本用法。try 语句用于包装可能抛出异常的代码,catch 语句用于捕捉 try 语句中的异常,...

    java 中finally语句块与return的执行关系

    Java 中 finally 语句块与 return 的执行关系 Java 中的 finally 语句块是用于保证无论出现什么情况,一定要执行的代码块。...我们需要了解 finally 语句块的作用和执行顺序,以便编写正确和高效的 Java 代码。

    Java finally语句到底是在return之前还是之后执行?

    在Java编程语言中,`finally`语句块是一个非常关键的结构,用于确保特定代码无论在...理解`finally`的执行顺序对于编写健壮的、易于维护的代码至关重要。在实际开发中,我们应该充分利用这一特性来提高代码的可靠性。

    关于Java中try finally return语句的执行顺序浅析

    "Java中try finally return语句的执行顺序浅析" 关于Java中try finally return语句的执行顺序浅析是Java语言中一个重要的知识点,今天我们来探讨一下try finally return语句的执行顺序。 首先,需要了解的是...

    try-catch-finally执行顺序验证

    try-catch-finally执行顺序验证(左边是.java文件,右边是.class文件) 提示: try、catch块内的return操作编译后会变成把return的值保存到变量var的操作。 总结: try、catch块内的return操作编译后会变成把return的值...

    try catch finally的执行顺序深入分析

    在编程语言中,异常处理是一种重要的错误处理机制,它允许我们优雅地捕获并处理运行时可能出现的问题。...理解这个执行顺序对于编写健壮的代码至关重要,特别是在处理资源管理和异常恢复的场景下。

    浅谈Java中return和finally的问题

    2. **`return` 与 `finally` 的执行顺序**:在 `try` 块中遇到 `return` 时,会先执行 `finally` 语句块,然后再返回值。这是因为 `finally` 中的代码优先级高于 `return`,即使 `return` 已经被触发,`finally` ...

    浅谈Java finally语句到底是在return之前还是之后执行(必看篇)

    Java 中 finally 语句的执行顺序探讨 在 Java 中,finally 语句的执行顺序是一个常见的探讨话题。很多人都认为 finally 语句一定会被执行,但这是不正确的。在某些情况下,finally 语句可能不会被执行,例如在 try ...

    对python中的try、except、finally 执行顺序详解

    总结来说,Python 中的 `try`、`except` 和 `finally` 执行顺序如下: 1. 先执行 `try` 块。 2. 如果在 `try` 块中发生异常,执行与之匹配的 `except` 块。 3. 不管是否发生异常,都会执行 `finally` 块。 4. 如果 `...

    Java中finally和return的关系实例解析

    在Java中,finally语句可以与return语句结合使用,但是它们的执行顺序是非常重要的。finally语句是在try的return语句执行之后,return返回之前执行的。这意味着,如果在try块中执行了return语句,finally语句将在...

    java面试题之try中含return语句时代码的执行顺序详解

    在涉及`return`语句时,其执行顺序可能会引起混淆,尤其是在`finally`块中有操作的情况下。让我们深入探讨一下这个面试题以及相关的知识点。 首先,`finally`块的特性是它总是在`try`或`catch`块执行完毕后执行,...

    java finally块执行时机全面分析

    以下是一个简单的例子来展示`finally`块的执行顺序: ```java public class FinallyTest { public static void main(String[] args) { int r = test(); System.out.println(r); } public static int test() { ...

    Java异常发生时程序的执行顺序

    - 示例 `T2` 中,`try` 里的 `return` 使得 `catch` 和 `finally` 之后的代码不被执行,但 `finally` 还是会执行。 - 示例 `Mine` 展示了文件操作异常的处理。当文件不存在时,`FileInputStream` 构造函数会抛出 `...

    AtividadesJava:Java执行顺序

    描述中的“Sequência de exercícios em Java”进一步确认了这是关于Java编程中的执行顺序问题,这通常涉及到程序控制流的概念,如顺序执行、条件判断和循环。 在Java中,程序的执行顺序遵循一定的规则: 1. **源...

    java面试精华7

    - 如果`try`块和`finally`块都有`return`语句,`finally`块的`return`会覆盖`try`块的`return`。这是因为在`return`语句执行后,返回值会被保存,然后`finally`块的代码执行,最后函数真正返回。如: ```java ...

    Java选择题.pdf

    8. try-catch-finally执行顺序:当try块中的return语句执行时,finally块的代码会在return之前执行。因此,选项C正确。 9. 异常处理和返回值:在try-catch-finally结构中,finally块的return语句总是最后执行,所以...

    C#中的try catch finally用法分析

    即使在`try`或`catch`块中有`return`语句,`finally`块的代码也会被执行。 ```csharp finally { // 无论是否发生异常都会执行的代码 } ``` 在示例中,无论`j`的值是否为0,`finally`块的`Console.WriteLine(j....

    trycatchfinaly

    #### 五、try-catch-finally 的执行顺序 1. **正常执行**:如果`try` 块内的代码正常执行完毕(没有抛出异常),则执行`finally` 块。 2. **异常发生**:如果`try` 块内的代码抛出了异常,并且有对应的`catch` 块...

    多线程计数实现多线程执行后再执行主线程

    通过以上分析,我们可以看到使用`CountDownLatch`来协调多线程执行顺序是一种非常有效的方式。这种方式不仅能够简化程序设计,还能够提高系统的稳定性和健壮性。在实际项目开发中,合理地利用这种技术可以有效地解决...

Global site tag (gtag.js) - Google Analytics