`
joknm
  • 浏览: 62827 次
  • 性别: Icon_minigender_1
  • 来自: 南宁
社区版块
存档分类
最新评论

finally 浅谈

    博客分类:
  • JAVA
 
阅读更多
近日做程序时突发奇想:try ... finally ... 中的 finally 会在返回前执行(在XXX书上看到的,忘了书名了),是于做了以下测试
public class FinallyTest 
{
	public static void main(String args[])
	{
		System.out.println("return: " + new FinallyTest().getString());
	}
	
	public String getString()
	{
		String returnString = null;
		try
		{
			returnString = "this string will be return.";
			return returnString;		
		}finally
		{			
			System.out.println("execute finally...");
			System.out.println("before clean returnString's value: " + returnString);
			returnString = null;
			System.out.println("after  clean returnString's value: " + returnString);
			System.out.println("execute finally end.");
		}		
	}
}

测试结题:
execute finally...
before clean returnString's value: this string will be return.
after  clean returnString's value: null
execute finally end.
return: this string will be return.

如果返回前执行,那么返回的字符串应该为空。但从结果来看,似乎出人的意料之外。
考虑原因:返回前将返回的结果拷贝了。

于是做了以下修改:
public class FinallyTest 
{
	public static void main(String args[])
	{
		System.out.println("return: " + new FinallyTest().getMessage().message);
	}
	
	public Message getMessage()
	{
		Message returnMessage = new Message();
		try
		{
			returnMessage.message = "message";
			return returnMessage;		
		}finally
		{			
			System.out.println("execute finally...");
			System.out.println("before clean returnString's value: " + returnMessage.message);
			returnMessage.message = null;
			System.out.println("after  clean returnString's value: " + returnMessage.message);
			System.out.println("execute finally end.");
		}		
	}
}

class Message
{
	public String message = "message";
}


结果:
execute finally...
before clean returnString's value: message
after  clean returnString's value: null
execute finally end.
return: null

从结果来看,只调用了对象的引用,而对象没有被拷贝。
看来,如所下用 finally 统一处理一般数据类型还是免谈了。
public class FinallyTest 
{
	public static void main(String args[])
	{
		System.out.println("return: " + new FinallyTest().getInt());
	}
	
	public int getInt()
	{
		int returnInt = 0;
		try
		{
			returnInt = 1;
			throw new RuntimeException("...");
		}catch(Exception e)
		{
			returnInt = 2;
			return returnInt;
		}finally
		{			
			System.out.println("execute finally...");
			System.out.println("before switch returnInt's value: " + returnInt);
			switch(returnInt)
			{
				case 1:
					returnInt = 0;
					break;
				case 2:
					returnInt = 3;
					break;
				default:
					returnInt = 4;
			}
			System.out.println("after  switch returnInt's value: " + returnInt);
			System.out.println("execute finally end.");
		}		
	}
}
分享到:
评论
41 楼 ghy_20081010 2011-01-05  
String 是常量 重新赋值意味着创建新对象 finally 与 return 不是同一对象引用地址。 用类封装则不同。
40 楼 zhangkaitao 2011-01-03  
   public class FinallyTest   
   {  
       public static void main(String args[])  
        {  
            System.out.println("return: " + new FinallyTest().getString());  
        }  
          
        public String getString()  
        {  
           String returnString = null;  
           try  
           {  
               returnString = "this string will be return.";  
               return returnString;          
           }finally  
           {             
               System.out.println("execute finally...");  
               System.out.println("before clean returnString's value: " + returnString);  
               returnString = null;  
              System.out.println("after  clean returnString's value: " + returnString);  
              System.out.println("execute finally end.");  
          }         
      }  
  }  


  今天又看这段代码,想起来问什么了?String是不可变类型,比如"a" + "b" 会生成一个新的对象,
  如
String a = “1”;
b = a;

会如何呢?复制,肯定是复制,即首先复制a的值,然后放如b是不?
因此return也是同样道理,首先把“returnString”的值复制出来是不,然后return回去。

 
39 楼 anhaoy 2010-07-30  
Danteng 里面 无限递归了,必然有   StackOverflowError
但是 就算出 StackOverflowError ,也还是要执行 finally ,所有 还是 有很多很多输出。。。。
38 楼 caohonghui725 2010-07-30  
yangguo,您确定您试过这个代码么?根本跟LZ的结果不一样啊!
37 楼 lianglaiyang 2010-07-30  
这个问题其实可以分成两步来解答:
1、try...finally中变量的关系是跟方法参数传递一样的。
2、方法参数传递只有值传递,没有引用传递。


所以要理解这个问题,就要理解方法中参数是怎么传递,而这个问题之前已有高手写过贴子!
36 楼 IcyFenix 2010-07-30  
hardPass 写道
改成

catch(Throwable e)

也不报StackOverflowError

奶奶的,为啥子?


} catch (Throwable e) {
    flag.set(false);
}

看看你的程序还会不会打印。
35 楼 IcyFenix 2010-07-30  
hardPass 写道

关键是没有看到异常,e.printStackTrace();


= =# 孩子,细心一些。

catch(Exception e) --> catch (Throwable e),我都提示是SOF错了,还放一个exception来抓?

34 楼 fyf_008 2010-07-30  
joknm 写道
我只是想知道一下是不是正的如其它人所说任东西需要后期处理的东西(比如数据链接释放之类的)都可以话到 finally 里面去处理。





请务必相信我的,我这个才是正确的,不关你看了什么书,

我的这个说法,是 java 作者告诉我的———玩笑玩笑。。

33 楼 zhaohaiyang 2010-07-30  
这问题其实比较无聊,楼主估计一时蛋疼
32 楼 hardPass 2010-07-30  
改成

catch(Throwable e)

也不报StackOverflowError

奶奶的,为啥子?
31 楼 hardPass 2010-07-30  
IcyFenix 写道
hardPass 写道

下面的程序打印出第一次执行"finally"的深度
打印出来的值是5761、5730、5515,每次结果还都不一样

但是,我觉得,不应该执行finally,因为try还没有执行完,danteng......

public static void main(String[] args) {
		doSomething();
	}
	
	static AtomicBoolean flag = new AtomicBoolean(true);
	static AtomicInteger count = new AtomicInteger(0);
	static void doSomething() {
		//int x = count.get();
		//if(x>100)
		//	return;
		count.incrementAndGet();

		try {
			//System.out.println("try..." + x);
			doSomething();
		}catch(Exception e){
			e.printStackTrace();
		}
		finally {
			if(flag.get()){
			System.out.println("finally" + count.get());
			flag.set(false);
			return;
			}
			
			doSomething();
		}
	}




别蛋疼了,退出不一定要return,抛异常而已可以。这里有StackOverflowError出现,finally当然会执行。


关键是没有看到异常,e.printStackTrace();
30 楼 IcyFenix 2010-07-30  
hardPass 写道

下面的程序打印出第一次执行"finally"的深度
打印出来的值是5761、5730、5515,每次结果还都不一样

但是,我觉得,不应该执行finally,因为try还没有执行完,danteng......

public static void main(String[] args) {
		doSomething();
	}
	
	static AtomicBoolean flag = new AtomicBoolean(true);
	static AtomicInteger count = new AtomicInteger(0);
	static void doSomething() {
		//int x = count.get();
		//if(x>100)
		//	return;
		count.incrementAndGet();

		try {
			//System.out.println("try..." + x);
			doSomething();
		}catch(Exception e){
			e.printStackTrace();
		}
		finally {
			if(flag.get()){
			System.out.println("finally" + count.get());
			flag.set(false);
			return;
			}
			
			doSomething();
		}
	}




别蛋疼了,退出不一定要return,抛异常而已可以。这里有StackOverflowError出现,finally当然会执行。
29 楼 zhangkaitao 2010-07-30  
我觉得这是jdk设计者故意设计的,finally 是在try 和 catch 返回之前做,但返回的值已经被提前保存了,所以会出现这种情况,这就说明jdk是传值而非引用,如果是引用就不会有这个问题。
28 楼 drift_ice 2010-07-30  
joknm 写道
drift_ice 写道
public class T{
    public int test(){
        int a=0;
        try{
            return a;
        }finally{
            a++;
        }
        
    }
    
    public static void main(String[] args){
        T t=new T();
        System.out.println(t.test());
    }
}


其中方法test的字节码如下:

public int test();
  Code:
   0:   iconst_0     #0,1:对应int a=0;
   1:   istore_1
   2:   iload_1      #2,3:对应int result=a;
   3:   istore_2
   4:   iinc    1, 1 #4:对应a++
   7:   iload_2      #7,8:对应return result
   8:   ireturn
   9:   astore_3     #9:对应Exception e
   10:  iinc    1, 1 #10:对应a++
   13:  aload_3      #13:,14:对应throw e
   14:  athrow
  Exception table:
   from   to  target type
     2     4     9   any
     9    10     9   any


首先,明确finally干了什么事?
其实class里并没有直接支持finally的机制,编译时finally中的内容会出现在两处地址(以上4行和10行),第一处是在执行try-catch中的代码后,第二次是出现在出现异常时。

其次,怎么返回值
如上2-8行所述,首先是将要返回的值保存在另一个本地变量的位置(istore_2),注意,这个跟a的变量位置1是不同的位置,相当于会先保存需要要返回基本类型的值或者对象的引用到某个变量中,然后再返回这个变量。

结论:所以返回时a的值确实是1,但是返回的并不是a,而是编译器为我们设置隐藏的变量result,其值为0

同理,如果是返回对象,如
public class T{
    public A test(){
        A a=new A();
        try{
            return a;
        }finally{
            a.i++;
        }
        
    }
    
    public static void main(String[] args){
        T t=new T();
        System.out.println(t.test().i);
    }
    
    static class A{
        public int i=0;
    }
}


不妨猜猜会返回多少


听君分析豁然开朗。
请教下以下的是用什么来查看的?
public int test();
  Code:
   0:   iconst_0     #0,1:对应int a=0;
   1:   istore_1
   2:   iload_1      #2,3:对应int result=a;
   3:   istore_2
   4:   iinc    1, 1 #4:对应a++
   7:   iload_2      #7,8:对应return result
   8:   ireturn
   9:   astore_3     #9:对应Exception e
   10:  iinc    1, 1 #10:对应a++
   13:  aload_3      #13:,14:对应throw e
   14:  athrow
  Exception table:
   from   to  target type
     2     4     9   any
     9    10     9   any



javap -c xxx
27 楼 joknm 2010-07-30  
drift_ice 写道
public class T{
    public int test(){
        int a=0;
        try{
            return a;
        }finally{
            a++;
        }
        
    }
    
    public static void main(String[] args){
        T t=new T();
        System.out.println(t.test());
    }
}


其中方法test的字节码如下:

public int test();
  Code:
   0:   iconst_0     #0,1:对应int a=0;
   1:   istore_1
   2:   iload_1      #2,3:对应int result=a;
   3:   istore_2
   4:   iinc    1, 1 #4:对应a++
   7:   iload_2      #7,8:对应return result
   8:   ireturn
   9:   astore_3     #9:对应Exception e
   10:  iinc    1, 1 #10:对应a++
   13:  aload_3      #13:,14:对应throw e
   14:  athrow
  Exception table:
   from   to  target type
     2     4     9   any
     9    10     9   any


首先,明确finally干了什么事?
其实class里并没有直接支持finally的机制,编译时finally中的内容会出现在两处地址(以上4行和10行),第一处是在执行try-catch中的代码后,第二次是出现在出现异常时。

其次,怎么返回值
如上2-8行所述,首先是将要返回的值保存在另一个本地变量的位置(istore_2),注意,这个跟a的变量位置1是不同的位置,相当于会先保存需要要返回基本类型的值或者对象的引用到某个变量中,然后再返回这个变量。

结论:所以返回时a的值确实是1,但是返回的并不是a,而是编译器为我们设置隐藏的变量result,其值为0

同理,如果是返回对象,如
public class T{
    public A test(){
        A a=new A();
        try{
            return a;
        }finally{
            a.i++;
        }
        
    }
    
    public static void main(String[] args){
        T t=new T();
        System.out.println(t.test().i);
    }
    
    static class A{
        public int i=0;
    }
}


不妨猜猜会返回多少


听君分析豁然开朗。
请教下以下的是用什么来查看的?
public int test();
  Code:
   0:   iconst_0     #0,1:对应int a=0;
   1:   istore_1
   2:   iload_1      #2,3:对应int result=a;
   3:   istore_2
   4:   iinc    1, 1 #4:对应a++
   7:   iload_2      #7,8:对应return result
   8:   ireturn
   9:   astore_3     #9:对应Exception e
   10:  iinc    1, 1 #10:对应a++
   13:  aload_3      #13:,14:对应throw e
   14:  athrow
  Exception table:
   from   to  target type
     2     4     9   any
     9    10     9   any

26 楼 drift_ice 2010-07-30  
public class T{
    public int test(){
        int a=0;
        try{
            return a;
        }finally{
            a++;
        }
        
    }
    
    public static void main(String[] args){
        T t=new T();
        System.out.println(t.test());
    }
}


其中方法test的字节码如下:

public int test();
  Code:
   0:   iconst_0     #0,1:对应int a=0;
   1:   istore_1
   2:   iload_1      #2,3:对应int result=a;
   3:   istore_2
   4:   iinc    1, 1 #4:对应a++
   7:   iload_2      #7,8:对应return result
   8:   ireturn
   9:   astore_3     #9:对应Exception e
   10:  iinc    1, 1 #10:对应a++
   13:  aload_3      #13:,14:对应throw e
   14:  athrow
  Exception table:
   from   to  target type
     2     4     9   any
     9    10     9   any


首先,明确finally干了什么事?
其实class里并没有直接支持finally的机制,编译时finally中的内容会出现在两处地址(以上4行和10行),第一处是在执行try-catch中的代码后,第二次是出现在出现异常时。

其次,怎么返回值
如上2-8行所述,首先是将要返回的值保存在另一个本地变量的位置(istore_2),注意,这个跟a的变量位置1是不同的位置,相当于会先保存需要要返回基本类型的值或者对象的引用到某个变量中,然后再返回这个变量。

结论:所以返回时a的值确实是1,但是返回的并不是a,而是编译器为我们设置隐藏的变量result,其值为0

同理,如果是返回对象,如
public class T{
    public A test(){
        A a=new A();
        try{
            return a;
        }finally{
            a.i++;
        }
        
    }
    
    public static void main(String[] args){
        T t=new T();
        System.out.println(t.test().i);
    }
    
    static class A{
        public int i=0;
    }
}


不妨猜猜会返回多少
25 楼 joknm 2010-07-30  
我只是想知道一下是不是正的如其它人所说任东西需要后期处理的东西(比如数据链接释放之类的)都可以话到 finally 里面去处理。

fyf_008 写道
楼主回答有些许问题。。

对象绝对没有 Copy. 或者说是克隆。你要用Java,就要知道Java的设计者如何设计java .这问题就解决



那为什么呢,

return obj;

只是 将返回引用(returnPointer),指向了obj 这个引用 指向的对象,

并没有Copy,

虽然,你在 finally 里面,把obj=null;
那只是, obj 这个引用,指向发生了变化,没有影响返回引用(returnPointer)




我原以为基本数据类型是以拷贝的形式传回值的(某些书上说的),现在由你这么说我也不知道谁对谁错了,有机会再去了解一个是怎么个传值回来的。

wujiazhao88 写道
楼主你试下这个程序看看,看看能不能猜到运行结果。

public class Danteng{
public static void main(String[] args){
 doSomething();
}

static void doSomething(){

try{
 System.out.println("try...");
 doSomething();
}finally{
System.out.println("finally");
doSomething();
}
}

}




这个问题确实很是 Danteng 1000多次以前都不会执行 finall ,4000次以后才会执行 finally。 这个问题够蛋疼的。
24 楼 superheizai 2010-07-30  
fyf_008 写道
楼主回答有些许问题。。

对象绝对没有 Copy. 或者说是克隆。你要用Java,就要知道Java的设计者如何设计java .这问题就解决



那为什么呢,

return obj;

只是 将返回引用(returnPointer),指向了obj 这个引用 指向的对象,

并没有Copy,

虽然,你在 finally 里面,把obj=null;
那只是, obj 这个引用,指向发生了变化,没有影响返回引用(returnPointer)



同意。
在执行到return语句的时候,return的其实是obj的地址。你对指向String的obj来说,任何操作改变的只是obj的指向,而不会改变String的内容。而楼主第二个例子,指向的是一般对象,对obj的改变同时也改变了其初始指向地址空间的值。
个人浅见,说错无怪
23 楼 sunliao_first 2010-07-30  
。。。。。
22 楼 hardPass 2010-07-30  

下面的程序打印出第一次执行"finally"的深度
打印出来的值是5761、5730、5515,每次结果还都不一样

但是,我觉得,不应该执行finally,因为try还没有执行完,danteng......

public static void main(String[] args) {
		doSomething();
	}
	
	static AtomicBoolean flag = new AtomicBoolean(true);
	static AtomicInteger count = new AtomicInteger(0);
	static void doSomething() {
		//int x = count.get();
		//if(x>100)
		//	return;
		count.incrementAndGet();

		try {
			//System.out.println("try..." + x);
			doSomething();
		}catch(Exception e){
			e.printStackTrace();
		}
		finally {
			if(flag.get()){
			System.out.println("finally" + count.get());
			flag.set(false);
			return;
			}
			
			doSomething();
		}
	}


相关推荐

    浅谈Java中return和finally的问题

    在Java编程语言中,`return` 语句和 `finally` 语句的相互作用是一个重要的概念,尤其是在处理异常处理时。`finally` 语句块通常用于确保某些代码无论是否发生异常都会被执行,而 `return` 语句用于提前结束方法并...

    浅谈java!

    - **异常处理**:学会正确使用try-catch-finally语句处理异常情况。 - **输入输出流**:熟悉文件读写操作,包括文本文件和二进制文件的处理。 - **泛型与注解**:了解泛型和注解的使用方法及其重要性。 #### 二、...

    浅谈Java异常.pdf

    同时,Java也提供了finally代码块,无论是否发生异常,finally块中的代码都会被执行。 异常处理并不是异常程序的首选方式,而是程序的一种补充手段。在编写程序时,应当尽量预防异常的发生,比如进行输入数据的校验...

    浅谈java之IO学习经验

    } finally { try { if (fis != null) fis.close(); if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } ``` ### 总结 本文介绍了Java IO的基础知识,包括流的概念、...

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

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

    Java分布式应用学习笔记06浅谈并发加锁机制分析

    ### Java分布式应用学习笔记06浅谈并发加锁机制分析 #### 1. 前言 在深入探讨Java中的并发加锁机制之前,我们有必要回顾一下多线程环境下的一些基本概念和技术。之前的多线程调度、并发调度以及线程加锁安全等内容...

    浅谈软件安全设计(一)

    浅谈软件安全设计(一) code by 黑夜彩虹 & vxin with almost pure delphi 网站:http://soft.eastrise.net 2007-03-07 --- 转载时请保留作者信息。 **************************************...

    浅谈基于Java的异常处理机制.pdf

    异常处理的三个主要概念是:异常类(Exception),异常处理语句(try, catch, finally),以及异常对象。异常类是在程序中定义异常条件的类。异常处理语句用于捕获和处理异常,而异常对象则是通过异常类的实例化而...

    浅谈西门子PLC的SCL语言编程_SCL手册_scl教程_

    西门子PLC的SCL(Structured Control Language)是一种基于IEC 61131-3标准的高级编程...通过阅读"浅谈西门子PLC的SCL语言编程.pdf"这份教程,新手可以逐步掌握SCL编程的核心概念和技巧,从而在自动化领域中得心应手。

    浅谈使用ADO.NET和ASP.NET访问SQL Server数据库.pdf

    由于提供的【部分内容】中大部分内容均为乱码,无法从中提取出有意义的IT知识点,但是根据标题“浅谈使用***和***访问SQL Server数据库.pdf”和【描述】中的重复标题,我们可以推断出本文档的主要内容。以下将围绕**...

    java之浅谈深说--教你如何成长

    ### Java之浅谈深说——教你如何成长为Java编程高手 在IT行业中,Java作为一种广泛使用的编程语言,其重要性不言而喻。对于希望成为Java编程高手的学习者来说,掌握正确的学习路径至关重要。本文将根据提供的标题、...

    浅谈Java自定义异常在教学中的教与学

    在代码块中可能发生异常的位置,可以使用try块来包含可能发生异常的代码,使用catch块来捕获和处理异常,而finally块则用于定义无论是否发生异常都需要执行的代码,比如释放资源、关闭文件等。 在Java程序设计语言...

    浅谈Python中的异常和JSON读写数据的实现

    - `finally`:可选,无论是否有异常发生,都会执行此块中的代码,通常用于释放资源等操作。 #### 示例分析 文章中的示例代码展示了如何使用异常处理来优雅地处理分母为零的情况: ```python def division...

    浅谈JavaScript异常处理语句

    此外,try-catch-finally结构还包括了finally块,无论try块中是否发生错误,finally块中的代码都会执行。这通常用于资源清理,比如关闭文件句柄、释放DOM元素引用等,确保程序的资源得到妥善处理,防止内存泄漏。 ...

    论文研究-基于Java异常处理机制的研究 .pdf

    Java异常处理结构包括try、catch和finally三个基本代码块。 - try块用于包裹可能会抛出异常的代码段。 - catch块用于捕获try块中抛出的异常,可以有多个catch块来捕获不同类型的异常。 - finally块用于执行清理工作...

    浅谈Java并发编程之Lock锁和条件变量

    "浅谈Java并发编程之Lock锁和条件变量" Lock锁是Java并发编程中的一种重要机制,它提供了比synchronized更加广泛的锁定操作。Lock接口有三种实现类:ReentrantLock、ReetrantReadWriteLock.ReadLock和...

    浅谈java异常处理之空指针异常

    1. `try`块不能单独存在,必须与`catch`、`finally`配合使用,形成`try...catch...finally`、`try...catch`或`try...finally`结构。 2. `try`、`catch`、`finally`块中的变量作用域独立,无法相互访问。若需共享变量...

    浅谈Python的异常处理

    5. `finally`: 不管是否发生异常,`finally`块中的代码都会被执行。这对于资源清理(如关闭文件、网络连接)非常有用。 6. `else`: 如果`try`块中的代码没有引发异常,那么`else`块的代码将会被执行。这通常用于在...

    浅谈java异常链与异常丢失

    异常丢失通常发生在`try-catch-finally` 结构中,特别是当finally块中抛出了新的异常,可能导致前面try块中抛出的异常信息丢失。如下所示: ```java public class MyTest { public void open() throws Exception {...

Global site tag (gtag.js) - Google Analytics