zoukankan      html  css  js  c++  java
  • java —— 异常中的陷阱(四)

    一、使用 finally 正确关闭资源的方式

      finally 块无论程序是否异常总是会被执行,因此常用来关闭物理资源,从而保证资源总能被关闭。

    import java.io.*;
    
    public class CloseResource {
    
    //一个函数同时读取两个文件
    
    public void readTwoFile() throws FileNotFoundException, IOException{
    
        BufferedReader br1 = null;
    
        BufferedReader br2 = null;
    
        FileReader fr = null;
    
        try{
    
            fr = new FileReader("A.txt"); //1
    
            br1 = new BufferedReader(fr); 
    
            int count = br1.read();    //2
    
            //process code1....
    
            fr = new FileReader("B.txt"); //3
    
            br2 = new BufferedReader(fr);
    
            count = br2.read(); //4
    
            //process code2
    
        }finally{
    
            if(br1 != null){
                
                try {
                    br1.close(); //5
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
            if(br2 != null){
                
                 try {
                    br2.close(); //6
                } catch (Exception e) {
                    e.printStackTrace();
                }  
            }    
        }
    }

      这样的关闭方式更加安全保证了,使用 finally 块来关闭物理资源,保证关闭操作总是会被执行; 关闭每个资源之前首先保证引用该资源的引用变量不为 null ; 为每个物理资源使用单独 try...catch 块关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭。

    二、finally 与 return 

    代码1:

    public class TestDemo {
        /**
         *     count=5
         *  int i =++count ; 先加1后赋值给i --> 6
         *  int i =count++ ; 先赋值给i再加1 --> 5
         * @return
         */
        public static int test(){
            int count = 5;
            try{
                //有finally块,不会立即 return 
                //finally 有return ,这里的return 不执行
                return ++count; 
            } finally{
                System.out.println("---finally----"+count);
                return count++;
            }
        
        }
    
        public static void main(String args[]) {
            
            System.out.println(test());
        }
    }
        "输出结果:"
        ---finally----6
            6

      当Java 程序执行try 块、catch 块时遇到了return 语句,return 语句会导致该方法立即结束。

      上述代码,系统执行完return 语句之后,并不会立即结束该方法,而是去寻找该异常处理流程中是否包含finally 块,如果没有finally 块,方法终止,返回相应的返回值。如果有finally 块,系统立即开始执行finally 块——只有当finally 块执行完成后,系统才会再次跳回来根据return 语句结束方法。如果finally 块里使用了return 语句来导致方法结束,则finally 块已经结束了方法,系统将不会跳回去执行 try 块、 catch 块里的任何代码。

    代码2:

    class Test {
        public int test() {
            int x = 1;
    
            try {
                return ++x;
            } catch (Exception e) {
    
            } finally {
                ++x;
            }
            return x;
        }
    
        public static void main(String[] args) {
            Test t = new Test();
            int y = t.test();
            System.out.println(y);
        }
    }

      输出结果: 2

    如果try语句里有return,那么代码的行为如下:

    1.如果有返回值,就把返回值保存到局部变量中

    2.执行指令跳到finally语句里执行

    3.执行完finally语句后,返回之前保存在局部变量表里的值 

      注意:如果你在finally里也用了return语句,比如return ++x。那么y会是3。因为规范规定了,当try和finally里都有return时,会忽略try的return,而使用finally的return

    代码3:

    public static int test() {
            int count = 5;
            try {
    
                throw new NullPointerException("异常报错");
            } finally {
                System.out.println("finally");
                return count;
            }
        }
    
        public static void main(String args[]) {
            System.out.println(test());
        }
        
        输出结果:
        finally
            5

      当程序执行 try 块、 catch 块时遇到 throw 语句时, throw 语句会导致该方法立即结束,系统执行 throw 语句时并不会立即抛出异常给方法的调用者,而是去寻找该异常处理流程中是否包含 finally 块。如果没有 finally 块,程序立即抛出异常;如果有 finally 块,系统立即开始执行 finally 块——只有当 finally 块执行完成后,系统才会再次跳回来抛出异常。如果 finally 块里使用 return 语句来结束方法,系统将不会跳回去执行 try 块、 catch 块去抛出异常。

    三、不要用 catch 代替流程控制

    public class TestDemo {
        public static void main(String args[]) {
            int [] arr = {1,2,3,4,5,6};
            int i = 0;
            try{
                while(true){
                    System.out.println(arr[i++]);
                }
            }catch(IndexOutOfBoundsException e){
                return;//结束循环
            }        
        }
    }

      异常机制不是为流程控制而准备的,异常机制只是为程序的意外情况准备的,因此程序只应该为异常情况使用异常机制。所以,不要使用这种“别出心裁”的方法来遍历数组。

    四、RuntimeException类

      RuntimeException的子类往往可以由用户选择性进行处理,如果不需要也可以不处理。

    范例:将字符变成数字

    public static void main(String[] args) {
    	Integer.parseInt("1234");
    }
    	
    "Integer类之中parseInt()方法的定义"	
    
     public static int parseInt(String s) throws NumberFormatException

      发现在parseInt()方法定义的时候存在有throws关键字的抛出,按照之前所学,既然此处存在有throws,那么在调用时就应该使用try…catch进行处理。可是此时没有强迫性的要求使用异常处理,来观察一下NumberFormatException定义:

    java.lang.Object
    
       |- java.lang.Throwable
    
          |- java.lang.Exception
    
             |- java.lang.RuntimeException
    
                |- java.lang.IllegalArgumentException
    
                   |- java.lang.NumberFormatException

      可以发现NumberFormatException不仅仅是Exception的子类,最重要的是,它还继承了RuntimeException,而在Java之中为了方便用户处理(并不是所有的异常都必须强制性处理),那么RuntimeException的子类往往可以由用户选择性进行处理,如果不需要也可以不处理。

    问题:请解释Exception和RuntimeException的区别?请列举出几个你常见的RuntimeException子类?

    • 用户可以处理的异常都要继承Exception类,而RuntimeException是Exception的子类;
    • Exception的异常要求用户强制性进行处理,而RuntimeException异常用户可以选择性进行处理,如果用户在编写代码过程之中没有处理,则出现异常后会由JVM进行默认处理。
    • 常见的RuntimeException子类(写出三、四个就可以):ArithmeticException、ClassCastException、NullPointerException、NumberFormatException、DOMException。

    五、继承得到的异常

      Java 语言规定,子类重写父类方法时,不能声明抛出比父类方法类型更多、范围更大的异常。也就是说,子类重写父类方法时,子类方法只能声明抛出父类方法所声明抛出的异常的子类

  • 相关阅读:
    Mybatis oracle多表联合查询分页数据重复的问题
    The Decade of Deep Learning
    D3S – A Discriminative Single Shot Segmentation Tracker
    Recent Advancements in NLP
    A list of datasets directly related to Music Information Retrieval Datasets
    Best Resources for Imbalanced Classification
    Attention-based Dropout Layer for Weakly Supervised Object Localization
    Learning a Discriminative Filter Bank within a CNN for Fine-grained Recognition
    Batch DropBlock Network for Person Re-identification and Beyond
    Cross-channel Communication Networks
  • 原文地址:https://www.cnblogs.com/SacredOdysseyHD/p/8412536.html
Copyright © 2011-2022 走看看