Bootstrap

Java异常处理【复习计划】

异常


异常是指运行期出现的错误

异常的概念

  1. Java异常是Java提供的用于处理程序中错误的一种机制。
  2. 所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0滋出,数组下标越界,所要读取的|文件不存在)。
  3. 设计良好的程序应该在异常发生时提供处理这些错误的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。
  4. Java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
  5. 当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
try{
    可能出错语句
}catch(错误类型+对象名称){
    对象名称.getMessage();  //得到有关异常的信息
    对象名称.printStackTrace();  //用于更新异常事件
}

异常分类

Throwable:

在这里插入图片描述

  1. Error (系统错误,无法处理)
  2. Exception
    (1). runtimeException (时常出现错误的异常,可以catch,也可不必catch)
    (2). …… ( 必须catch ,在api文档中,方法含有throw关键字的 )
    注:在一一个try语句块中,基类异常捕获语句不可以在子类异常捕获语句上;
Error
  • Error是程序无法处理的错误,表示程序在运行中出现了问题,表示代码运行时JVM(Java虚拟机)出现的问题,这些错误是不可查的,因为他们在应用程序的处理和控制能力之外的,所以即使发生了错误,本质上也不应该试图去处理它所引起的异常情况。
Exception
  • Exception异常分为两大类,运行时异常和非运行时异常
RuntimeException

运行时异常是不可查异常,程序中可以选择捕获,也可以不进行处理,常见的有:IndexOutOfBoundsException(下标越界异常)、NullPointerException(空指向异常)……,程序中应该从逻辑角度尽量避免。
在Java编译阶段不会检查,也就是说当可能出现该种错误的语句并没有使用try-catch语句进行捕获,也是会编译通过的

// 以下是我前段时间写的一个从键盘获取Int类型值的方法,这样处理可以防止输入出错导致程序退出
public static int getNumber(){
		Scanner scanner=new Scanner(System.in);
        int number=0;
        try{
            number=scanner.nextInt();
        }catch (InputMismatchException e){
            System.out.println("请检查输入是否有误!!!");
            getNumber();
        }
        return number;
    }
其他Exception

是RuntimeException以外的异常,类型上都属于Exception类及其子类,属于可查异常
即程序编写时就必须进行捕获处理、或者抛出的异常,否则就会导致编译不通过
如IOException、SQLException等以及用户自定义的Exception异常

异常机制即运行逻辑

异常处理的机制

Java中的异常处理机制为:抛出异常、捕获异常

  1. 抛出异常:当一个方法执行出错而引发异常时,方法会创建异常对象并交付给运行时系统,运行时系统则会去寻找处理异常的代码并执行
    • 抛出异常通过throw关键字进行异常抛出,从方法中抛出异常需要使用throws关键字
// 例如java IO流中关闭输入输出流对象时的方法就会向外抛出IOException
public void close() throws IOException{
	// ……
}


// 以下为抛出一个自定义异常的代码片段
class MyException extends Exception {
    private int id;
    public MyException(String message, int id){
        super(message);
        this. id=id;
        public int getId(){
            return id;
      }
}
    
    public class Test{
        public void regist(int num)throws MyException{
            if(num<0{
                throw nlkw MyException("人数为负值,不合理”,3); // 使用throw抛出异常
            }
            system.out.println("登记人数"+num);
              public void manager(){
              try{regist(100);}
              catch(MyException e){
              System.out.println
             (”登记失败,出错类型码="+e.getId());
              e.printStackTrace();
           }
           System.out.print("操作结束");
      }
        public static void main(string[]args){
            Test t=new Test();t.manager();
   }
  1. 捕获异常:在方法抛出异常后,运行时系统开始寻找合适的异常处理器(exception handler),潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合,当异常处理器所能处理的异常类型和抛出的异常类型相符即为合适的异常处理器。运行时系统从发生异常的地方开始,依次回查调用栈中的方法,直到找到含有合适的处理器的方法并执行,如果没有找到,则运行时系统将会终止,同时也意味着Java程序的终止
    • 捕获异常通过try-catch 或 try-catch-finally 语句实现

Java所要求的异常处理方式

  1. Error:对于方法运行中可能出现的Error,Java允许该方法不做任何抛出声明,因为大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常
  2. RuntimeException:由于RuntimeException的不可查性,为了合理更容易的实现程序,Java规定运行时异常将由运行时系统自行抛出,允许运用程序忽略运行时异常
  3. 其余Exception(可查异常):对于所有的可查异常,Java规定:一个方法必须捕捉,或者声明时抛出方法之外(throws关键字)。
运行逻辑
// 基本语法
try{
	//可能出错的代码
}catch(异常对象1声明){   // 例:Exception e
	//对应的异常处理代码
}catch(异常对象2声明){
	//对应异常2的异常处理代码
}finall{
	//无论是否出现错误都会执行的代码
}
  • try 包裹的语句块叫做监控区域,Java方法中运行出现异常,就将异常抛出到监控区域外,由Java运行时系统寻找匹配的catch子句进行匹配,try后可以跟0个或多个catch语句块,如果没有catch语句块,则必须跟一个finally语句块

    • 匹配原则:如果抛出的异常对象属于catch子句的异常类或属于该异常类的子类,则认为认为生成的异常对象与catch块捕捉的异常类型相匹配
    • 注意:当某个catch子句捕获到匹配的异常对象,将会进入异常处理代码,处理结束后就意味着try-catch语句结束,其他的catch语句将不会再有匹配和捕获异常的机会(因此需要将更为具体的Exception类放在大类型的前面进行匹配(可以理解为优先将异常子类放在异常父类前进行捕捉))
  • finaly关键字
    位于catch后面,无论异常是否出现都会执行finaly块中的语句

    1. finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态作统一的管理。
    2. 无论try所指定的程序块中是否抛出异常,finally所指定的代码都要被执行。
    3. 通常在finally语句中可以进行资源的清除工作,如:
      ◆关闭打开的文件
      ◆删除临时文件
  • try、catch、finall 语句块的执行顺序

  1. 当try语句块中并未捕获到异常,则按顺序执行,并跳过catch语句块,执行finally语句块和后面语句
  2. try 捕获到异常,但没有找到合适的catch语句块处理异常时,就会抛给JVM(Java虚拟机)进行处理,finally语句块中的语句还是会执行,但是finally后的语句不会执行
  3. try 捕获到异常,且找到对应的catch语句块时:在try语句中按顺序执行,当出现异常时,程序跳到catch语句块,并进行逐一进行匹配,找到对应的匹配程序,其他的catch语句将不会被执行,而try语句块中,出现异常后的语句也不会被执行,catch语句执行完以后执行finally语句,最后执行finally语句块后的语句。

使用自定义异常

使用目定义并吊一按有则下步浆:

  1. 通过继承 java.lang.Exception类声明自己的异常类。
  2. 在方法适当的位置生成自定义异常的实例,并用throw语句抛出。
  3. 在方法的声明部分用throws语句声明该方法可能抛出的异常。
class MyException extends Exception {
    private int id;
    public MyException(String message, int id){
        super(message);
        this. id=id;
        public int getId(){
            return id;
      }
}
    
    public class Test{
        public void regist(int num)throws MyException{
            if(num<0{
                throw nlkw MyException("人数为负值,不合理”,3);
            }
            system.out.println("登记人数"+num);
                public void manager(){
                try{regist(100);}
                catch(MyException e){
                    System.out.println
                        (”登记失败,出错类型码="+e.getId());
                        e.printStackTrace();
                }
                System.out.print("操作结束");
            }
        public static void main(string[]args){
                Test t=new Test();t.manager();
        }

声明并抛出异常

注意:重写方法需要抛出与原方法所抛出类型一致的异常或抛出异常

关于finally的问题

  1. finally语句块中的语句一定会执行嘛?
    • 会,但是是建立在程序正常执行的情况下,那什么时候finally语句块中代码不会执行呢?
      1)在finally语句块中发生了异常。
      2)在前面的代码中用了System.exit()退出程序。
      3)程序所在的线程死亡。
      4)关闭CPU。

总结

一张图,五个关键字(throws、throw、try、catch、finaly)
先catch小的,再catch大的
异常和重写的关系(重写方法需要抛出与原方法所抛出类型一致的异常或抛出异常)

文章参考https://blog.csdn.net/qq_29229567/article/details/87286739

;