面向对象(五)——异常

Keywords: trycatchfinallythrowsthrow

异常

异常的概述

异常: 程序在运行时出现不正常的情况,在java中用类的形式对不正常情况进行了描述和封装对象。描述不正常的情况的类,就称为异常类。

异常的体系:
Throwable

  • Error:通常出现重大问题如:运行的类不存在或者内存溢出等。对于Error一般不编写针对性的代码对其进行处理。
  • Exception:运行过程中出现的非严重问题。对于Exception可以使用针对性的处理方式进行处理:try catch finally

无论Error或者Exception都具有一些共性内容,比如:不正常情况的信息,引发原因等。

ErrorException的子类名都是以父类名作为后缀。

异常的处理格式

格式一:

try
{
    需要被检测的代码;
}
catch(异常类 变量)
{
    处理异常的代码:(处理方式);
    System.out.println(e.getMessage());
    System.out.println(e.toString());
    e.printStackTrace();
}
finally
{
    一定会执行的语句;
}

格式二:

try{}
catch(异常类 变量){}

格式三:

try{}
finally{}

finally代码块: 一定执行的代码,通常用于关闭资源。
特殊情况:finally代码块只有一种情况不会被执行,就是在之前执行了System.exit(0)

异常抛出过程:
[图片上传失败...(image-699426-1589686886273)]

try catch异常处理过程
[图片上传失败...(image-926d13-1589686886273)]

记住:catch是用于处理异常的,如果没有catch就代表异常没有被处理过,如果该异常时检测时异常,那么必须被抛出。

Throwable中的方法(day11\ExceptionDemo3.java)
getMessage():获取异常信息,返回字符串。
toString():获取异常类名和异常信息,返回字符串。
printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。JVM默认的异常机制就是在调用此方法打印异常在堆栈中的跟踪信息
printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。

throwsthrow关键字

异常体系最大的特点就是体系中的类以及类产生的对象,都具备可抛性,可抛性的意思是可以被throwsthrow所操作。只有异常体系具备这个特点。

throws关键字

对多异常的处理:

  1. 声明异常时,建议声明更为具体的异常,这样处理得可以更具体
  2. 对方声明几个异常,就对应有几个catch块,不要定义多余的catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

建议在进行catch处理时,catch中一定要定义具体处理方式。不要简单定义一句e.printStackTrace();,也不要简单的就书写一句输出语句。

一个栗子:

class Demo
{
    public int div(int a,int b)throws ArrayIndexOutOfBoundsException, ArithmeticException
    {
        int[] arr = new int[4];
        System.out.println(arr[a]);//throw new ArrayIndexOutOfBoundsException抛给调用者
        return a/b;//throw new ArithmeticException("/ by zero")抛给调用者
    }
}

class  ExceptionDemo
{
    public static void main(String[] args)//throws Exception
    {
        Demo d = new Demo();
        try
        {
            int num = d.div(4,0);
            System.out.println("num="+num);
        }
        catch(ArrayIndexOutOfBoundsException e)
        {
            System.out.println(e.toString());
            System.out.println("数组角标越界");
        }
        catch(ArithmeticException e)
        {
            System.out.println(e.toString());
            System.out.println("除数为0");
        }
        System.out.println("over");
    }
}

自定义异常与throw关键字

项目中会出现特有的问题,而这些问题并未被java所描述并封装对象,所以对于这些特有的问题可以按照java对问题封装的思想,将特有的问题进行自定义的异常封装。(day11\ExceptionDemo7.java)

自定义类继承Exception或者RuntimeException。原因:1.为了让该自定义类具备可抛性;2.让该类具备操作异常的共性方法。

当要定义自定义异常的信息时,可以使用父类已经定义好的功能。异常信息传递给父类的构造函数

一个栗子:

需求:在上面的程序中,对于除数时-1,也视为时错误的,无法进行运算,那么就需要对这个问题进行自定义的描述。

class FuShuException extends Exception
{
    //定义异常信息:因为父类中已经把异常信息的操作都完成了,
    //所以子类只要在构造时,通过super语句将异常信息传递给父类,
    //那么就可以直接通过getMassage方法获取异常信息了
    FuShuException(String message)
    {
        super(message);
    }
}

class Demo
{
    public int div(int a,int b)throws FuShuException
    {
        if(b<0)
            throw new FuShuException;
        return a/b;
    }
}

class  ExceptionDemo
{
    public static void main(String[] args)//throws Exception
    {
        Demo d = new Demo();
        try
        {
            int num = d.div(4,-1);
            System.out.println("num="+num);
        }
        catch(FuShuException e)
        {
            System.out.println(e.toString());
            System.out.println("除数为负");
        }
        System.out.println("over");
    }
}

当在函数内部出现了throw抛出异常对象,那么就必须给给出对应的处理动作,要么在内部try catch处理,要么在函数上声明(可抛可try),让调用者处理。一般情况下,函数内出现异常,函数上需要声明。

throwsthrow的区别

  • 位置不同:
    1. throws使用在函数上,throw使用在函数内
    2. throws抛出的是异常类,可以抛出多个,用逗号隔开;throw抛出的是异常对象。
  • 功能不同:throws用来声明异常,让调用者知道该功能有可能出现的问题,并由调用者可以给出预先的处理方式;throw抛出具体问题对象,执行到throw功能就已经结束了,跳转到调用者,并将具体的问题也抛给调用者。

特殊子类异常RuntimeException

RuntimeException及其子类如果在函数内抛出该异常,函数上可以不用声明,编译一样通过;如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过。

之所以不用在函数上声明,是因为不需要调用者处理,该异常发生,希望程序停止,因为在运行时出现了无法运算的情况,希望停止程序后对代码进行修正。

自定义异常时,如果该异常发生,无法再继续进行运算,就让自定义异常继承RuntimeException

异常的分类:

  1. 编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。 这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。如果没有处理(没有抛也没有try),编译失败。
  1. 编译时不检测异常(运行时异常):就是Exception中的RuntimeException及其子类。这种问题的发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的而或者引发了内部状态的改变导致的。那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。

异常在子父类覆盖中的体现

  1. 子类在覆盖父类时,如果父类的方法抛出异常,那么子类覆盖方法,只能抛出父类的异常或者该异常的子类;
  2. 如果父类方法抛出多个异常,那么子类在覆盖该方法时只能抛出父类异常的子集;
  3. 如果父类或接口的方法中没有异常抛出,那么子类在覆盖方法时也不可以抛出异常,如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。

异常的应用

  1. 毕老师用电脑上课,分析其中的问题,比如电脑蓝屏、冒烟……(day11\ExceptionTest.java)
  2. 有一个圆形和长方形,都可以获取面积,如果出现非法数值,视为是获取面积出现问题,通过异常来表示。(day11\ExceptionTest1.java)

总结

异常的好处:

  1. 将问题进行封装
  2. 将正常流程代码和问题处理代码相分离,便于阅读

异常的处理原则:

  1. 处理方法有两种:try或者throws
  2. 调用到抛出异常的功能时,抛出几个,处理几个。一个try对应多个catch
  3. 多个catch,父类的catch往下放
  4. catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace或输出语句,也不要不写
    当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
    try{
        throw new AException();
    } catch(Aexception e){
        throw e;
    }
    
    如果该异常处理不了,当需要将异常产生的和本功能相关的问题提供出去,让调用者知道并处理。也可以将捕获异常处理后,转换新的异常抛出。
    try{
        throw new AException();
    } catch(AException e){
        //对AException先处理
        throw new BException();
    }
    

异常的注意事项: 在子父类覆盖时

  1. 子类抛出的异常必须时父类异常的子类或者子集;
  2. 如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。