• Java 进阶6 异常处理的陷阱


    Java 进阶6 异常处理的陷阱 20131113
    异常处理机制是 Java语言的特色之一,尤其是 JavaChecked 异常,更是体现了 Java语言的严谨性:没有完善的错误的代码根本就不会被执行。对于 Checked异常,Java 程序要么声明抛出,要不使用 try .. catch捕获程序运行过程中抛出的异常,进行处理。 Java开发程序员都是无法回避异常处理的情况, Java异常处理同样存在着一些迷惑的地方。例如在 finally代码块执行的规则是怎样的?程序中遇到 return语句之后还会执行finally代码块吗?程序遇到 System.exit()的时候还会执行finally代码块吗?
    1. 正确关闭资源的方式
              实际的开发过程中经常需要打开一些物理资源,比如数据库连接、网络连接、磁盘文件等等,打开这些资源的之后必须要显式的关闭资源,否则会引起资源的泄漏。虽然 JVM有垃圾回收机制,但是对于这些资源, JVM是不会回收这些资源的, JVM只能够回收内存,而不能回收资源。
              传统的方式关闭资源,在 finally
             finally{
             oos.close();ois.close(); 回收资源,但是这种方式不一定是安全的,因为在 oos ois未初始化的时候,程序运行就发生异常的话,那么 oosois 为完成初始化,这样的话, oosois 是没有必要关闭的。所以使用下面的方式关闭资源的话,是一种相对稳妥的方式。也就是在关闭之前,判断这些资源是否是有效的。
    }
    finally{if(oos != null) {oos.close();}  if(ois!= null ) { ois.close() ;}}
    使用finally关闭资源的方式是比较安全的,保证关闭操作总是被执行;当关闭资源的时候,确保资源的引用变量是有效的资源而不是 null;为每个物理资源使用单独的 try…catch关闭资源,保证关闭资源的时候,引发的异常不会影响其他资源的关闭。
    Java7中引入的新的自动关闭资源的 try语言:它允许在try关键字之后紧跟一对圆括号,圆括号中可以声明,初始化一个或者多个资源,此处的资源是那些必须在程序结束的时候显式的关闭的资源。,比如数据库连接,网络服务等等。当 try语句结束的时候就会自动关闭这些资源。
    需要注意的是为了保证 try语句正常关闭资源,这些资源类需要实现 AutoCloseable或者是Closeable 接口,实现这两个接口就需要实现 close方法。
     
    try(
             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“a.bin”));
             ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“a.bin”));
    ){
    oos.writeObject(obj);
    oos.flush();
     
    Object obj2 =(Object) ois.readObject();
    }
    这样的话,当超出 try代码块的时候,就会自动关闭打开的资源。需要注意的两点:
              被关闭的资源必须是实现 Closeable或者是AutoCloseable 接口;被关闭的资源必须是在 ()中声明、初始化的。
    2.finally 代码块的陷阱
    public static void main(String[] args)  {
             // TODO Auto-generated method stub
            FileOutputStream fos = null;
             try {
                fos = new FileOutputStream("Base.java" );
                System. out.println("successful open resource" );
                System. exit(0);
                
            } catch (FileNotFoundException e) {
                 // TODO Auto-generated catch block
                e.printStackTrace();
            } finally{
                 if(fos !=null ){
                     try {
                        fos.close();
                    } catch (IOException e) {
                         // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System. out.println("the program success close resource" );
            }
        }
    这样的程序,不会输出 finally的内容。不论 try代码块是正常结束,还是中途非正常的推出, finally代码块都会执行,然而在这个程序中 try代码块根本就没有结束期执行过程,执行 exit的时候,将会停止当前线程还有所有其他当场死亡的线程, finally代码块不能够让停止的线程继续执行
         System.exit(0) 的时候,JVM退出之前需要完成两项的清理工作:执行系统中注册的所有关闭钩子;如果程序中调用了 System.runFinalizerOnExit(true);那么JVM 就会对还没有结束的对象调用 finalizer;第二种方式是十分危险的,所以一般不会提倡;第一种方式是比较安全的操作。程序中将关闭的操作注册为关闭钩子,在 JVM退出之前,这些关闭钩子就会被调用,保证物理资源被正常关闭。
    public static void main(String[] args) throws FileNotFoundException  {
             // TODO Auto-generated method stub
             final FileOutputStream fos;
            fos = new FileOutputStream("a.bin" );
            System. out.println(" 程序打开物理资源 ");
             Runtime.getRuntime().addShutdownHook(new Thread(){
                 public void run(){
                     if(fos != null ){
                         try {
                            fos.close();
                        } catch (IOException e) {
                             // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    System. out.println(" 程序正常关闭资源 ");
                }
            });
            System. exit(0);
        }
     
    Finally 代码块
    public static int test(){
             int count = 5;
             try{
                 return ++count;
            } finally{
                System. out.println("finally code block");
                 return count*2;
            }
            
        }
        public static void main(String[] args ) throws FileNotFoundException  {
             // TODO Auto-generated method stub
             int a = test();
            System. out.println(a);
        }
     Java程序中执行 try代码块的时候遇到 return代码的时候, return语句会导致该方法立即结束,系统执行完 return语句的时候,并不会立即结束该方法,而是去寻找该异常处理流程中是否包含 finally代码块,如果有的话,则会执行 finally代码块,结束完成之后,在回到原来的 return语句中结束该方法;但是如果在 finally中如果有 return代码的话,就会直接在 finally中结束该方法。
     
    Tengfei Yang
    于广州中山大学 20131113
  • 相关阅读:
    【01】Maven依赖插件之maven-dependency-plugin
    docker(六) 使用docker-maven-plugin插件构建docker镜像
    SpringBoot 打包配置去除第三方依赖包
    maven打包为jar文件时,解决scope为system的jar包无法被打包进jar文件的解决方案。
    SpringBoot入门之spring-boot-maven-plugin
    SpringBoot系列之—瘦身部署
    java之mybatis之模糊查询
    java之mybatis之查询及分页
    java之mybatis之占位符
    java之mybatis之使用mybatis实现crud操作
  • 原文地址:https://www.cnblogs.com/hbhzsysutengfei/p/3438849.html
Copyright © 2020-2023  润新知