• 第十二章 使用finally进行清理


    finally语句什么时候用:

    你没必要在finally语句里处理内存回收,因为内存回收会由垃圾回收器完成,finally语句通常用于内存回收之外的情况。当要把除内存之外的资源恢复到它们初始状态时,就要用到finally子句。这种需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形,甚至外部世界的某个开关。

    package 异常.Finally;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class Fin {
    
        public static void main(String[] args) {
            test();
        }
        
        public static void test() {
            File file = null;
            FileInputStream in = null;
    
            file = new File("C:/Users/admin/Desktop/12.xls");
            try {
                in = new FileInputStream(file);
                System.out.println("打开成功!");
            }catch(FileNotFoundException e) {
                System.out.println("创建File对象时,未找到指定文件,此时文件流构造失败,并未被打开!");
                e.printStackTrace();
            }catch(Exception e){
                System.out.println("任何其他捕获异常的catch块子句必须关闭文件");
                System.out.println("因为在他们捕获到异常之时,文件已经打开了");
                try {
                    if(in != null) {
                        in.close();
                    }
                } catch (IOException ie) {
                    e.printStackTrace();
                }
            }finally {
                //不能在这里关闭流,因为流从未被打开过
            }
            
        }
    
    }

    控制台:

    创建File对象时,未找到指定文件,此时文件流还未被打开!
    java.io.FileNotFoundException: C:UsersadminDesktop12.xls (系统找不到指定的文件。)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(Unknown Source)
        at java.io.FileInputStream.<init>(Unknown Source)
        at 异常.Finally.Fin.test(Fin.java:20)
        at 异常.Finally.Fin.main(Fin.java:11)

    finally语句怎么用才恰当:

    对于在构造阶段可能会抛出的异常,并且要求清理的类,最安全的使用方式是使用嵌套的try子句

    更恰当的写法:

    package 异常.Finally;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    
    public class Fin {
    
        public static void main(String[] args) {
            test();
        }
        
        public static void test() {
            File file = null;
            BufferedReader bf = null;
    
            file = new File("C:/Users/admin/Desktop/new 1.txt");
            try {
                bf = new BufferedReader(new FileReader(file));
                try {
                    while(bf.readLine() != null) {
                        System.out.println(bf.readLine());
                    }
                }catch(Exception e) {
                    e.printStackTrace();
                }finally {
                    if(bf!=null) {
                        bf.close();
                    }
                }
            }catch(Exception e) {
                System.out.println("FileInputStream对象构造失败");
            }        
        }
    
    }

    只有在流构建成功时,才要去保证流对象被清理。使用嵌套的基本规则就是:在创建需要清理的对象之后,立即进入下一个try-finally语句块。

    finally语句不受break与continue影响:

    package 异常.Finally;
    
    public class FinallyTest {
        
        static void test() {
            int i = 0;
            while(true) {
                try {
                    if(i < 1) {
                        i++;
                        continue;
                    }else {
                        break;
                    }
                }catch(Exception e) {
                    e.printStackTrace();
                }finally {
                    System.out.println("我不受break/continue影响!");
                }
            }
            
            
        }
    
        public static void main(String[] args) {
            test();
        }
    
    }

    控制台:

    我不受break/continue影响!
    我不受break/continue影响!

    在return中使用finally:

     1 package 异常.Finally;
     2 
     3 public class FinallyTest {
     4     
     5     static int test() {
     6         int i = 0;
     7         try {
     8             return i++;
     9         }catch(Exception e) {
    10             e.printStackTrace();
    11         }finally {
    12             System.out.println("我不受return影响!");
    13         }
    14         return 10;
    15     }
    16 
    17     public static void main(String[] args) {
    18         System.out.println(test());
    19     }
    20 
    21 }

    控制台:

    我不受return影响!
    0

    看以看出finally被执行了。return即代表程序结束,但finally却被执行了,可以说明finally语句块肯定是在return之前执行的。但经过断点调试(断点位置:6 ,8 ,12),我却发现以上断定是错误的,程序是先执行了6,然后执行了8,在之后才执行12,最后又执行了8。感觉好像return专门给finally开了一个小灶,在return之前先执行一下finally语句,然后就直接return结束程序。

    finally与return到底有什么样的联系?

     1 package 异常.Finally;
     2 
     3 public class FinallyTest {
     4     
     5     static int test() {
     6         int i = 0;
     7         try {
     8             return i;
     9         }catch(Exception e) {
    10             e.printStackTrace();
    11         }finally {
    12             i = i + 5;
    13             System.out.println("我不受return影响!");
    14         }
    15         return 10;
    16     }
    17 
    18     public static void main(String[] args) {
    19         System.out.println(test());
    20     }
    21 
    22 }

    控制台:

    我不受return影响!
    0

    断点位置依旧如上,再次调试,发生了不可思议的问题,当执行完finally之后,i 确实变为了5,而且在最后执行return时,此时鼠标放在 i 上也真真切切的是 i = 5;但是最后打印的结果还是 0 !似乎return只记住了最开始的 i 值,之后对 i 的操作,都被无视了。

    当把基本数据类型换为引用类型时:

    package 异常.Finally;
    
    import java.util.Arrays;
    
    public class FinallyTest {
        
        static int[] test() {
            int[] i = {1,2,3};
            try {
                return i;
            }catch(Exception e) {
                e.printStackTrace();
            }finally {
                i[2] = 10;
                System.out.println("我不受return影响!");
            }
            return null;
        }
    
        public static void main(String[] args) {
            System.out.println(Arrays.toString(test()));
        }
    
    }

    控制台:

    我不受return影响!
    [1, 2, 10]

    莫名的对于引用类型发生改变时,却没有被return无视。

    基本类型是在栈中声明的,引用类型则在堆中。当return第一次发生时就应该把值或地址【当然地址也算是值】从栈中给弹出了,最后一次执行return时就直接使用最开始弹出的值或地址而不使用经finally改变后的,但由于引用类型是在堆中进行了操作,当最后拿着最初的地址去到堆里查找输出时,堆里的内容已经改变。地址的值和基本类型的值一样,二者都没有发生改变,只是堆内容改变了,再次寻找时,结果也变了,但是基本类型的值已经被弹出,并不受finally中的改变,所以还是原来的值。

    finally里的return会层叠try或catch里的return:

     1 package 异常.Finally;
     2 
     3 
     4 public class FinallyTest {
     5     
     6     @SuppressWarnings("finally")
     7     static int test() {
     8         int i = 1;
     9         try {
    10             return i;
    11         }catch(Exception e) {
    12             e.printStackTrace();
    13         }finally {
    14             i = 5;
    15             System.out.println("我不受return影响!");
    16             return i;
    17         }
    18     }
    19 
    20     public static void main(String[] args) {
    21         System.out.println(test());
    22     }
    23 
    24 }

    控制台:

    我不受return影响!
    5

    debug后发现,并没有二次执行第10行,而是执行finally里的return后就结束了。似乎就是finally会层叠掉try或catch【已测试过】里的return。

    学习thinking in java,结合网上各位大佬的观点,特此总结。

    前进时,请别遗忘了身后的脚印。
  • 相关阅读:
    Oracle 安装报错 [INS-06101] IP address of localhost could not be determined 解决方法输入日志标题
    Linux下安装oracle数据库提示DISPLAY not set. Please set the DISPLAY and try again。
    redhat 关机注销命令详解
    VirtualBox的四种网络连接方式
    修改RedHat的系统显示时间
    insufficient memory to configure kdump(没有足够的内存)解决方法(待验证、待解决)
    xen坑随笔 heartbeat dpkg垃圾数据库清除
    tomcat 监控脚本
    负载均衡随笔
    GIT命令介绍
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/9260338.html
Copyright © 2020-2023  润新知