Java异常总结

作者: 阿Q说代码 | 来源:发表于2019-03-05 17:01 被阅读0次

    Throwable

    Error:严重问题,通常出现重大问题如:运行的类不存在或者内存溢出,服务器宕机,数据库崩溃等等。出现了error,靠我们的异常处理方式 try{}catch(){}和throws是处理不了的,必须找出哪个地方犯了这么严重的错误,然后修改代码,改正确了之后,程序才能够运行起来,否则程序绝对运行不起来。

    代码演示:

    public class Test {
        public static void main(String[] args) {
            show();
        }
    
        private static void show() {            
            show();     //java.lang.StackOverflowError栈内存溢出,这种情况必须更改代码
        }
    }   
    

    Exception

    Exception下面RuntimeException下面的儿子都是运行期异常。运行时期异常可以处理也可以不处理

    1)不处理:如果不处理,也不会报错(eclipse报红线),java就会用jvm默认的的处理方式,它就把异常的类型、原因、位置直接显示在了控制台。并且退出当前线程(可以理解为退出虚拟机),同时后面的代码是不能执行的。

    2)处理:为了让后面的代码继续执行,那么我们处理异常, 我们采用try{}catch(){}

    try{    
        可能发生问题的代码。  
    }catch(异常类名 变量名){
        变量名.printStackTrace();//异常处理代码。
    }finally{
        释放资源代码。(数据库,IO)
    }
    

    代码演示:

    public static void main(String[] args) {
        try{
            System.out.println(10/0);
        }catch(ArithmeticException a) { //ArithmeticException a = new ArithmeticException();
            System.out.println("出错了,除数为零了");    //打印出:出错了,除数为零了
        }
    
        System.out.println("1111111111111111"); //打印出:1111111111111111,不会影响后面代码的运行
    }
    

    注意事项:

    ①一个try里面有多个异常怎么办?可以一个try后面跟多个catch,但是如果异常是平级关系,没有顺序问题。如果异常存在着子父关系,父一定要放在最后。

    代码演示:

    public static void demo1() {
        int a = 10;
        int b = 0;
        int[] arr = {11,22,33,44,55};
        try {
            System.out.println(a / b);  //运行时报错
            System.out.println(arr[10]);    //此代码不会执行
            arr = null;         //此代码不会执行
            System.out.println(arr[0]); //此代码不会执行
        } catch (ArithmeticException e) {
            System.out.println("除数不能为零");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("索引越界了");
        } catch (Exception e) {         //Exception是父类  父类一定放在最后面 
            System.out.println("出错了");
        }
        System.out.println("over"); //不影响后面代码的运行
    }
    

    ②:可以用一个catch, catch里面写一个Exception就可以了

    代码演示:

    public static void demo1() {
        int a = 10;
        int b = 0;
        int[] arr = {11,22,33,44,55};
    
        try {
            System.out.println(a / b);
            System.out.println(arr[10]);
            arr = null;
            System.out.println(arr[0]);
        } catch (Exception e) {         //多态
            System.out.println("出错了");
        }                           
        System.out.println("over");
    }
    

    ③了解JDK7的新特性。格式:try{}catch(异常1 | 异常2 | 异常3 ... 变量名){}

    代码演示:

    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int[] arr = {11,22,33,44,55};
    
        //JDK7如何处理多个异常
        try {
            System.out.println(a / b);
            System.out.println(arr[10]);
        } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
            System.out.println("出错了");
        } 
    }
    

    ④我们一直在处理异常的时候都是打印的一句话,虽然提示了我们有错误,但是没有告诉开发人员是哪一行代码出错,没有告诉开发人员是哪个异常! 那这样的话,不利于开发人员对代码进行维护,所以我们就有了标准的异常catch代码,既能打印出异常消息,显示出哪一行出的错,又能不影响后面的代码执行。首先介绍:Throwable中的方法:

    public String getMessage():返回的是异常的消息字符串。

    public String toString():返回异常的简单描述信息。全路径类名 : 消息字符串

    public void printStackTrace():把错误信息显示在控制台。

    代码演示:

    public static void main(String[] args) {
        try {
            System.out.println(1/0);
        } catch (Exception e) {         //Exception e = new ArithmeticException("/ by zero");
            System.out.println(e.getMessage());//   / by zero
            System.out.println(e);      //java.lang.ArithmeticException: / by zero
            e.printStackTrace();        
            /*java.lang.ArithmeticException: / by zero at           com.heima.exception.Demo5_Throwable.main(Demo5_Throwable.java:18) 
                                                        */
        }
    }
    

    ⑤finally的程序除了虚拟机挂掉,其他的时候都会执行的,所以把一些必须要执行的重要代码放在finally里面执行。比如释放资源代码。
    ⑥final,finally和finalize的区别:

    • final可以修饰类,不能被继承;修饰方法,不能被重写;修饰变量,只能赋值一次

    • finally是try语句中的一个语句体,不能单独使用,用来释放资源

    • finalize是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法

    面试题

    如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。

    public static void main(String[] args) {
        System.out.println(method());       //30
    }
    public static int method() {
        int x = 10;
        try {
            x = 20;
            System.out.println(1/0);
            return x;
        } catch (Exception e) {
            x = 30;
            return x;   //当程序执行到这儿,内存中已经生成了一条"return 30"的路径,
            //但是发现finally还没有执行呢,就又去执行了finally里面的内容让x变成了40,
            //但是"return 30"的路径已经生成了,即使x变成了40也是没用的!
            //接着还是会继续执行"return 30" 然后结束方法。
        } finally {
            x = 40;                         
        }
    }
    

    ⑦如果处理运行期异常,我们还可以采用Throws 声明异常,但是我们一般不用(为什么?请看下面解释)。编译期异常:Exception下面非RuntimeException 的异常;运行期异常:RuntimeException下的异常。如果是运行期异常的话我们声明和不声明是一样的。而且只要运行时出现异常的话,声明和不声明异常,后面的代码都不会再继续执行了,那么我们为什么有个声明异常这种处理方式呢?这就引出了编译期异常,编译期异常就是在开发人员编写代码的时候,程序提示你这儿以后可能会出现一些常见的问题,让咱们在写代码的时候就要针对这常见的问题采取措施,不要等运行的时候出错了再去解决,因为这个问题很常见,可以预防,所以java呢为了这样提示开发人员就让开发人员在编写的时候都不让开发人员编译通过,必须要采取措施,而开发人员采取的措施一个就是用try{}catch(){} ,另一个就是不用管这个异常啦,直接抛给虚拟机(throws声明一下),这两种方式都证明开发人员知道这儿可能会出现异常,并采取措施了。 所以声明异常是给编译期异常准备的。 运行期异常虽然能用,但是没啥实际意义,所以运行期异常我们一般还是用try{}catch(){}。

    自定义异常

    有时候需要我们自己定义一些异常,很简单,只需要建一个类(类名见名知意) 继承这个异常体系(继承Exception或者其儿子),写一个有参构造方法用来传入异常信息,遇到特定业务的时候throw就可以了。

    代码演示:

    //建一个类(类名见名知意)继承这个异常体系(继承Exception或者其儿子)
    class AgeOutOfBoundsException extends Exception {   
      
        public AgeOutOfBoundsException() {
            super();
        }
        public AgeOutOfBoundsException(String message) {//写一个有参构造方法,用来传入异常信息
            super(message);             
        }       
    }
    
    public class Demo_Exception {
    
        public static void main(String[] args) throws Exception {//p.setAge(-17);main方法中调用setAge方法的时候,因为setAge方法体上声明了一个编译期异常 所以main方法的方法体上也要声明该编译期异常
            Person p = new Person();
            p.setAge(-17);
            System.out.println(p.getAge());
        }
    
    }
    
    class Person {
        private String name;
        private int age;
        public Person() {
            super();
        }
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) throws Exception{   
            //方法体内如果有 "throw 编译期异常对象" ,则方法体上必须用throws声明该编译期异常
            if(age >0 && age <= 150) {
                this.age = age;
            }else {
                throw new AgeOutOfBoundsException("年龄非法");  //遇到特定业务的时候throw就可以了
            }
        }
    
    
    }
    
    throw和throws的区别:

    throw 写在方法里面,后面跟对象,只能跟一个对象

    throws 写在方法声明上,后面跟异常类型,可以跟多个异常类型并用逗号隔开

    字符类关系中的异常

    a:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)

    class Fu{
        public void show() throws IOException{  //父类方法声明 IOException 
    
        }
    }
    class Son extends Fu{
      
        public void show() throws IOException{  //这样是可以的 声明和父类相同的IOException
    
        }
      
        public void show() throws FileNotFoundException{
            //这样是可以的,声明父类异常的儿子,也就是IOException的子类FileNotFoundException
    
        }
    
        public void show() throws Exception{
            //这样是不行的 声明父类异常的父类,也就是IOException的父类Exception
        }
                
    } 
    

    b:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常。

    class Fu{
        public void show() throws IOException,NoSuchMethodException{
    
        }
    }
    class Son extends Fu{
        public void show() throws IOException{//这样写可以 子类只能抛出相同的异常或者是他的子集
    
        }
       
        public void show() throws ParseException{//这样做是不行的 子类不能抛出父类没有的异常
    
        }
    
    }
    

    c:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常;如果子类方法内有异常发生,那么子类只能try,不能throws

    class Fu{
        public void show(){
    
        }
    }
    class Son extends Fu{
        public void show(){//这样做可以 如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常
    
        }
    
        public void show() throws Exception{//这样做 不可以
    
        }
    
        public void show() {
            //如果被重写的方法没有异常抛出,而且子类方法内有异常发生,那么子类只能try,不能throws    
            try {
                FileInputStream fis = new FileInputStream("xxx.txt");  
                //new FileInputStream("xxx.txt");这句话有个编译期异常
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    

    好了今天就先说到这了,明天继续。想了解更多学习知识,请关注微信公众号“阿Q说”,获取更多学习资料吧!你也可以后台留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

    相关文章

      网友评论

        本文标题:Java异常总结

        本文链接:https://www.haomeiwen.com/subject/xjuouqtx.html