异常及其处理(Java)

异常

异常:就是程序出现的不正常的情况。
举例:
错误:这是非常严重的问题,一般我们处理不了,一般在这里指的是硬件问题。
异常:
编译时期异常:开始就必须要处理的,如果不处理,后面就走不了。
运行时期异常:开始可以不用处理。这种问题一旦发生,就是我们的程序问题,需要我们修改程序。

体系结构:

Throwable:
Error:
Exception:
非RuntimeException:编译时期异常
RuntimeException:运行时期异常
在这里插入图片描述

例如:比如除数不能为0:java.lang.ArithmeticException: / by zero

public class ExceptionDemo2 {
    public static void main(String[] args) {
        System.out.println("start");
        int a = 10;
        int b = 0;
        System.out.println(a/b);//java.lang.ArithmeticException: / by zero
        System.out.println("end");
    }
}

针对异常,JVM默认的处理方案:

  • 一旦遇到程序出现了问题,就会把问题的类名,错误原因,错误的位置等信息打印在控制台,以便我们观察。并且,会自动从当前出问题的地方停止掉。
  • 这种处理方案虽然可以,但是不够好。 哪里不好呢?
    *其实程序出问题,不应该直接停止,因为我们的程序可能是由多部分组成的,其中一个部分出问题了,不应该影响其他部分的执行。
  • 所以,我们应该让其他的部分能够执行下去。

对于上面的问题我们有以下方案两种方案:
try…catch…finally
throws

try…catch…finally:

try{
可能出现异常的代码
}catch(异常类名 变量名) {
 针对异常的代码处理
}finally {
释放资源的地方
}
简化一下第一个:
try{
可能出现异常的代码
}catch(异常类名 变量名) {
针对异常的代码处理
}
public class ExceptionDemo3 {
    public static void main(String[] args) {
        System.out.println("start");
        int a= 10;
        int b = 0;
        try{
            //可能出现异常的代码
            System.out.println(a/b);//当除数为0的时候会抛出ArithmeticException这个异常
                                    //接着程序会拿着这个异常和catch里面的异常类已经对比                   
        }catch(ArithmeticException e){
            //当程序抛出ArithmeticException这个异常之后给出的具体的处理方法
            System.out.println("你的除数不能为0");
        }
        System.out.println("end");
    }
}

多个异常的处理:
1.针对每一个出现问题的地方写一个try…catch语句
2.针对多个异常,采用一个try,多个catch的情况。
try…catch…catch…
注意:有多个catch时候,运行时,只能运行出一个错误,而程序不会返回到try
例如下面的程序运行结果:不能运行出除数为0的结果,遇到try里面的问题,就自动和catch里面进行匹配。一旦匹配就执行catch里面的内容,执行完毕后,接着执行后面的代码。
注意:如果异常间有子父关系,父必须在最后。(因为如果异常放在前面,则发生异常的时候都会被父类异常接受,后面会报错)

package com.edu_01;
public class ExceptionDemo4 {
    public static void main(String[] args) {
        //多个异常处理的第一种解决方案
        //A:给每一个可能出现异常的代码全部加上try..catch..
/*      try{
            System.out.println(10/0);
        }catch(ArithmeticException e){
            System.out.println("除数不能为0");
        }
        int[] arr = {1,2,3};
        try{
            System.out.println(arr[3]);//抛出IndexOutOfBoundsException这个异常
        }catch(IndexOutOfBoundsException e){
            System.out.println("数组越界了");
        }*/
        //B:针对多个异常,采用一个try,多个catch的情况。
        //当存在多个catch情况下,如果异常类之间存在子父关系,那么父类应该放到最后
        int[] arr = {1,2,3};
        try{
            System.out.println(arr[3]);//抛出IndexOutOfBoundsException
            System.out.println(10/0);//抛出ArithmeticException
            arr = null;
            System.out.println(arr[2]);//抛出空指针异常NullpointerException
        }catch(IndexOutOfBoundsException e){//Exception e = new IndexOutOfBoundsException();
            System.out.println("数组越界了");
        }catch(ArithmeticException e){
            System.out.println("除数不能为0");
        }catch(Exception e){//当前面的异常类都没有匹配到之后,会自动匹配这个异常
            System.out.println("出现了其他异常");
        }
    }
}

编译时期异常和运行时期异常的区别:

  • 编译时期异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译
  • FileNotFoundException(文件未找到异常)
  • 运行时期异常:无需显示处理,也可以和编译时异常一样处理
  • ArithmeticException

Throwable中的方法:

  • printStackTrace():打印异常信息,程序从出问题的地方开始就会打印创建一个该异常对应的对象,该对象直接调用打印方法。
public class ExceptionDemo6 {
    public static void main(String[] args) {
        try{
            System.out.println(10/0);//当程序出问题了之后会抛出一个ArithmeticException的对象
            //new ArithmeticException()
        }catch(ArithmeticException e){//ArithmeticException e = new ArithmeticException();
            e.printStackTrace();//打印异常信息
            //java.lang.ArithmeticException: / by zero
            //at com.edu_01.ExceptionDemo6.main(ExceptionDemo6.java:12)
        }
    }
}

throws
表示抛出异常,由该方法的调用者来处理,用在方法声明后面,跟的是异常类名,可以跟多个异常类名,用“,”号隔开。
throws表示出现异常的一种可能,并不一定会发生这些异常。
try…catch 是直接进行了处理。而throws则是把异常处理的事情交给了调用者。throws用在方法上,声明方法有异常,交给调用者处理。但是呢,如果是编译时期异常,调用就必须处理。如果是运行时期异常,调用者可以处理,也可以不处理。

异常处理:
try…catch…finally
finally:一般用于释放资源。在数据库操作或者IO流比较常见。
特点:
被finally控制的语句体一定会执行
特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))

public class ExceptionDemo8 {
    public static void main(String[] args) {
        try{
            System.out.println(10/0);
        }catch(ArithmeticException e){
            System.out.println("除数为0了");
            //在执行finally语句体之前jvm虚拟机退出了,那么就不会被执行
            System.exit(0);
        }finally{
            //这个代码块里面的代码一定会被执行的
            System.out.println("我是finally我一定会被执行");
        }
    }
}

final,finally的区别:
final:最终的意思。可以修饰类,方法,变量。
修饰类,类不能被继承
修饰方法,方法不能被重写
修饰变量,变量是常量
finally:
异常处理的一部分。被finally控制的代码一定会执行。
特殊情况:在执行到finally之前,jvm退出了。

注意:
A:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
B:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
C:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
上述仅仅针对编译时期异常,与运行时期异常无关。

throw和throws的区别:
throws:
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw:
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常!
注意:如果throw的是编译时期异常,在方法声明上必须用throws进行标记,如果throw的是运行时期异常,在方法声明上可以用throws进行标记,也可以不用。

public class ThrowDemo {
    public static void main(String[] args) {
        method();
        try {
            method2();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    private static void method2() throws FileNotFoundException{
        try{
            FileInputStream fis = new FileInputStream("D://a.txt");
        }catch(FileNotFoundException e){
            //当遇见这个异常之后,直接抛出(这就是我给出的处理方法)
            //如果【抛出的是编译时期异常的话,必须在方法声明上给予声明
            throw new FileNotFoundException();
        }
    }
    private static void method() throws ArithmeticException{
        int a = 10;
        int b = 2;
        if (b==0) {
            //在这里抛出的是运行时期异常,抛出这个异常的同时,可以在方法声明上给予声明,也可以不声明
            throw new ArithmeticException();
        }else {
            System.out.println(a/b);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章