Java中异常

一、异常的概述

在Java中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置、原因等)。

二、异常的继承体系和错误的区别

1、异常的继承体系

Throwable: 它是所有错误与异常的超类(父类)

            |- Error 错误

            |- Exception 编译期异常,进行编译JAVA程序时出现的问题

                |- RuntimeException 运行期异常, JAVA程序运行过程中出现的问题

2、异常与错误的区别

异常:指程序在编译、运行期间发生了某种异常(XxxException),我们可以对异常进行具体的处理,若不处理异常,程序将会结束运行。如数组索引越界异常ArrayIndexOutOfBoundsException。

错误:指程序在运行期间发生了某种错误(XxxError),Error错误通常没有具体的处理方式,程序将会结束运行。Error错误的发生往往都是系统级别的问题,都是jvm所在系统发生的,并反馈给jvm的。我们无法针对处理,只能修正代码。如内存溢出错误OutOfMemoryError,开辟了过大的数组空间,导致JVM在分配数组空间时超出了JVM内存空间,直接发生错误

三、异常对象的产生原因和处理方式

1、以数组索引越界异常ArrayIndexOutOfBoundsException为例分析产生原因

当索引越界时,JVM能自动检测到问题,这个异常Java本身有描述:异常的名称、异常的内容、异常的产生位置,java将这些信息直接封装到异常对象中。new ArrayIndexOutOfBoundsException(4);

将异常的对象抛出,抛给方法的调用者(这里是main),main接收到这个异常后,并没有进行处理异常,main()方法就会继续把异常抛给调用者JVM

JVM接收到这个异常后,首先将异常信息以红色字体输出在控制台,然后终止程序      

2、异常的处理方式

JVM的默认处理方式:把异常的名称,原因,位置等信息输出在控制台,同时会结束程序。

解决程序中异常的手动方式:编写处理代码 try...catch...finally;抛出 throws

四、抛出异常throw和异常申明throws

在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。

1、抛出异常具体操作

创建一个异常对象,封装一些提示信息(信息可以自己编写)

通过关键字throw告诉调用者异常信息

2、使用格式

throw new 异常类名(参数);

eg:throw new NullPointerException("要访问的arr数组不存在");

        throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");

3、异常申明throws

申明:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。

格式:修饰符返回值类型方法名(参数) throws 异常类名1,异常类名2… {   }

throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开

public static void main(String[] args) throws Exception {

    int[] arr = {1,5,3,7};

    int index = arr.length;

    myException(arr,index);

}

public static void myException(int[] arr,int index) throws Exception {

    if(arr == null)

    {

        throw new Exception("该数组不存在!");

    }

    if(index < 0 || index >= arr.length)

    {

        throw new Exception("索引在数组中不存在!");

    }

}

五、try…catch…finally异常处理

捕获Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理

1、捕获异常的格式

try {

    //需要被检测的语句

}

catch(异常类 变量) { //参数

    //异常的处理语句

}

finally {

    //一定会被执行的语句

}

2、try…catch…组合(含多catch组合)

try:该代码块中编写可能产生异常的代码,当try检测到有异常发生,接收到一个异常的对象,便将异常的对象抛给catch代码块来处理

catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理,处理后程序继续执行

finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。可以用于释放资源。

public static void main(String[] args)

{

    int[] arr = {1};

    //对代码进行异常检测

    try{

        int a = getArry(arr);

        System.out.println(a);

    }

    //处理方式

    catch (NullPointerException ex)

    {

        System.out.println(ex);

    }

    //多catch处理方式

    catch (ArrayIndexOutOfBoundsException ex)

    {

        System.out.println(ex);

    }

    System.out.println("over!");

}

public static int getArry(int arr[])

{

    //对数组是否为空进行判断

    if(arr == null)

    {

        //手动抛出异常

        throw new NullPointerException("该数组不存在!");

    }

    //对数组索引进行判断

    if(arr.length < 3)

    {

        //手动抛出数组越界的异常

        throw new ArrayIndexOutOfBoundsException("数组没有3索引!");

    }

    return arr[3] + 1;

}

注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理

3、try...finally ...组合

try finally 组合对代码进行异常检测,检测到异常后因为没有 catch,所以一样会被默认jvm抛出,异常是没有捕获处理的,但是功能所开启的资源需要进行关闭,所有 finally 只为关闭资源。

void show(){    //需要throws

try{

    throw new Exception();

}finally {

//释放资源

}

}

六、运行时期异常

异常分为两种,一种是运行异常,另一种是编译异常。运行异常:抛出的异常是 RuntimeException 类,或者是他的子类;编译异常:调用了抛出异常的方法,不处理编译失败

运行异常特点

方法内部抛出的异常就是运行异常,new XXXException

方法的声明上不需要 throws 语句,调用者也无需处理此异常

运行异常,一旦发生,不要处理,而是修改源码,后面的代码没有执行的意义

七、异常在方法重写中的细节

在继承后,子类重写父类的方法时,异常处理注意事项

1、父类的方法抛出异常,子类重写后

可以不抛出异常

也可以抛出异常,但抛出的异常不能大于父类的异常(继承关系)

2、父类的方法没有抛出异常,子类重写后

不能抛出异常

如果子类中调用了抛出异常的方法,只能 try...catch...来处理异常

注:接口中没有声明异常,而当实现的子类重写方法时发生了异常,无法进行 throws 声明,只能 catch 捕获,如果问题还是处理不了,则在catch 中继续抛出,但是只能将异常转换为 RuntimeException 子类抛出

八、异常中常用的方法(Throwable 类方法)

在 Throwable 类中为我们提供了很多操作异常对象的方法

getMessage()方法:返回该异常的详细信息字符串,即异常提示信息

toString()方法:返回该异常的名称与详细信息字符串

printStackTrace()方法:在控制台输出该异常的名称与详细信息字符串、异常出现的代码位置

try{

    Person p = null;

    if(p == null)

    {

        throw new NullPointerException("出现空指针异常,请检查对象是否为null");

    }

}

catch(NullPointerException e)

{

    //返回该异常的详细信息字符串

    String message = e.getMessage();

    System.out.println(message);


    //返回该异常的名称与详细信息字符串

    String result = e.toString();

    System.out.println(result);

    //在控制台输出该异常的名称与详细信息字符串、异常出现的代码位置

    e.printStackTrace();

}

九、自定义异常

部分异常都是JDK内部定义好的,并且这些异常不好找,书写时很不方便,这时候就需要自己定义异常。JDK中是使用类在描述异常信息,因此可以模拟Java这种机制,自己定义异常的信息、异常的名字,让异常更符合自己程序的阅读,准确对自己所需的异常进行类的描述

1、自定义异常类的定义

通过阅读异常类源码可以发现,每个异常类都调用了父类的构造方法,把异常描述信息传递给了父类,让父类进行异常信息的封装

格式:

Class 异常名 extends Exception{    //或继承RuntimeException

    public 异常名(){

    }

    public 异常名(String s){

        super(s);   

    }

}


2、自定义异常类 

定义Person类,包含name与age两个成员变量

public class Person {

    String name;

    int age;

    public Person(String name, int age) throws myException {

        //加入逻辑判断,并设置抛出异常

        if(age < 0 || age > 200)

        {

            throw new myException("年龄格式不对" + age);

        }

        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) {

        this.age = age;

    }

    @Override

    public String toString() {

        return "Person{" +

                "name='" + name + '\'' +

                ", age=" + age +

                '}';

    }

}

自定义异常类

//自定义异常,继承Exception

public class myException extends Exception {

    myException(String message)

    {

        super(message);

    }

}

在main中调用

public static void main(String[] args)

{

    try

    {

        Person P = new Person("Tom",-1);

        System.out.println(P);

    }

    catch (myException e) {

        e.printStackTrace();

    }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,875评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,569评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,475评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,459评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,537评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,563评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,580评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,326评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,773评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,086评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,252评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,921评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,566评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,190评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,435评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,129评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,125评论 2 352

推荐阅读更多精彩内容