异常的捕获及处理

1. 异常的产生

异常是导致程序中断执行的一种指令流,异常一旦出现且没有对其进行合理的处理,程序就中断执行。
范例:不产生异常的代码

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        System.out.println("2.计算 " + (10/2));
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
2.计算 5
3.结束除法计算

范例:产生异常

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        //此行代码产生异常
        System.out.println("2.计算 " + (10 / 0));     
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:5)

异常一旦发生,产生异常的语句及之后的语句都不再执行,默认输出异常信息后,程序自动结束执行。
我们要做的就是:即使出现了异常,也应该让程序正确的执行完毕。

2. 处理异常

如果想要进行异常的处理,在Java之中提供了三个关键字:try、catch、finally,而这三个关键字的使用语法如下:

//“[]” 表示有可能使用到
try {
    //有可能出现异常的语句
} [ catch(异常类型 对象){
    //异常处理
}catch(异常类型 对象){
    //异常处理
}...] [finally {
    //不管是否出现异常,都执行的代码
}]

范例:应用异常处理try...catch

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        try {
            System.out.println("2.计算 " + (10 / 0));     
        } catch (ArithmeticException e){
            e.printStackTrace();
        }
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:6)
3.结束除法计算

由于使用了异常处理,即使程序出现了异常,也可以正常的执行完毕。而且使用异常类中提供的printStackTrace()方法,可以完整的输出异常信息。
范例:使用try...catch...finally

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        try {
            System.out.println("2.计算 " + (10 / 0));     
        } catch (ArithmeticException e){
            e.printStackTrace();
        } finally {
            System.out.println("不管是否有异常,都执行此语句!");
        }
        System.out.println("3.结束除法计算");
    }
}

输出显示:

1.开始除法计算
java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:5)
不管是否有异常,都执行此语句!
3.结束除法计算

3. 异常的处理流程(核心)

首先观察两个异常类的继承结构:


观察两个异常类

观察可以发现所有的异常类都是Throwable的子类,而在Throwable下有两个子类:
Error 和 Exception

  • Error :指的是JVM错误,即:此时的程序还没有执行,用户还无法处理;
  • Exception :指的是程序运行中产生的异常,用户可以处理。

也就是所谓的异常处理指的就是所有的Exception以及它的子类异常。

面试题:Java中的异常处理流程

异常处理流程

范例:使用Exception处理异常

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.开始除法计算");
        try {
            int x = Integer.parseInt(args[0]);
            int y = Integer.parseInt(args[1]);
            System.out.println("2.计算 " + (x / y));
            System.out.println("**************");
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            System.out.println("不管是否有异常,都执行此语句!");
        }
        System.out.println("3.结束除法计算");
    }
}

所有的异常都使用了Exception进行处理,所以在程序之中不用再去关心到底使用哪一个异常。
注意:

  • 在编写多个catch捕获异常的时候,捕获范围大的异常一定要放在捕获异常范围小的异常之后,否则编译错误。
  • 虽然直接捕获Exception比较方便,但是这样也不好,因为这样所有的异常都会安装同一方式处理。

4. throws关键字

throws关键字主要用于方法声明上,指的是当方法之中出现异常后交由被调用处来进行处理。
范例:使用throws

class MyMath {
    //存在throws关键字,表示此方法里面产生的异常交给调用处处理
    public static int div(int x , int y) throws Exception {
        return x / y ;
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

调用了具有throws声明的方法之后,不管操作是否出现异常,都必须使用try...catch来进行异常的处理。

5. throw关键字

在程序之中直接使用throw手工抛出一个异常类的实例化对象。
范例:手工抛出异常

public class ThrowDemo {
    public static void main(String[] args) {
        try {
            throw new Exception("自己定义的异常");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

输出显示:

java.lang.Exception: 自己定义的异常
    at ThrowDemo.main(ThrowDemo.java:4)

面试题:throws 和 throw的区别

  • throws:在方法的声明上使用,表示此方法在调用时必须处理异常;
  • throw:指的是在方法中人为抛出一个异常类对象(这个异常类对象可能是自己实例化或是抛出已知存在)。

6. 重要的代码模型:异常的使用格式

需求:要求定义一个div()方法,在进行计算之前打印提示信息,计算结束也打印提示信息,如果在计算之中产生了异常,则交给被调用处进行处理。
范例:不出错的代码

class MyMath {
    public static int div(int x , int y) {
        int result = 0;
        System.out.println("*** 1. 计算开始 ***");
        result = x / y;
        System.out.println("*** 1. 计算结束 ***");
        return result;
        
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
            System.out.println(MyMath.div(10 , 2));
    }
}

但是以上代码中的除法操作不一定永远都正常完成,所以应该进行合理的处理。首先,如果方法出现异常,必须交由调用处处理,所以应该在方法上使用throws抛出

class MyMath {
    //存在throws关键字,表示此方法里面产生的异常交给调用处处理
    public static int div(int x , int y) throws Exception {
        int result = 0;
        System.out.println("*** 1. 计算开始 ***");
        result = x / y;
        System.out.println("*** 1. 计算结束 ***");
        return result;
        
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果以上代码真的出错,程序的有些内容就不执行了,所以修改如下:

class MyMath {
    //存在throws关键字,表示此方法里面产生的异常交给调用处处理
    public static int div(int x , int y) throws Exception {
        int result = 0;
        System.out.println("*** 1. 计算开始 ***");
        try {
            result = x / y;
        } catch (Exception e) {
            throw e;    //继续抛异常
        } finally {
            System.out.println("*** 1. 计算结束 ***");
        }
        return result;
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 0));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出显示:

*** 1. 计算开始 ***
*** 1. 计算结束 ***
java.lang.ArithmeticException: / by zero
    at MyMath.div(ThrowsDemo.java:7)
    at ThrowsDemo.main(ThrowsDemo.java:19)

7. RuntimeException 类

先观察一段代码:

public class RuntimeExceptionDemo {
    public static void main(String[] args) {
        int temp = Integer.parseInt("100");
        System.out.println(temp);   //输出100
    }
}

在看一下parseInt()方法的定义:
public static int parseInt(String s) throws NumberFormatException
此时parseInt()方法上抛出了NumberFormatException,按理说,应该进行强制性的异常捕获,但是现在并没有强制性操作,所以来看下NumberFormatException的继承结构:

java.lang.Object 
    java.lang.Throwable 
        java.lang.Exception 
            java.lang.RuntimeException → 运行时异常
                java.lang.IllegalArgumentException 
                    java.lang.NumberFormatException

在Java里面为了方便用户代码的编写,专门提供了RuntimeException类,其特征为:程序在编译的时候不会强制性要求用户处理异常,用户可以根据需求选择性的进行处理,如果没有处理又发生了异常,则交给JVM默认处理。

面试题:Exception 和 RuntimeException的区别?列举几个常见的RuntimeException子类:

  • Exception是RuntimeException的父类;
  • 使用Exception定义的异常必须要被处理,而RuntimeException的异常可以选择性处理:
  • 常见的RuntimeException:ArithmeticException、NullPointerException、ClassCastException。

8. assert关键字—断言(了解)

assert关键字是在JDK1.4的时候引入的,其主要的功能就是进行断言。断言:指的是程序执行到某行代码处判断是否是预期的结果。
范例:观察断言

public class AssertDemo {
    public static void main(String[] args) {
        int num = 10;
        //中间可能经过了多行代码操作num的内容
        //期望中的内容是20
        assert num == 20 : "num的内容不是20";
        System.out.println("num = " + num);
    }
}

正常执行输出显示:
num = 10
启用断言执行:java -ea AssertDemo

Exception in thread "main" java.lang.AssertionError: num的内容不是20
        at AssertDemo.main(AssertDemo.java:6)

9. 自定义异常

Java本身提供了大量的异常,但是这些异常实际工作中并不够去使用,所以就需要用户自定义异常类。如果开发自定义的异常类可以选择继承Exception或者RuntimeException类。
范例:定义AddException

class AddException extends Exception{
    public AddException(String msg) {
        super(msg);
    }
}

public class AddExceptionDemo{
    public static void main(String[] args) {
        int num = 20;
        try {
            if (num > 0) {  //出现错误,应该产生异常
                throw new AddException("数值传递过大");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上代码知识介绍自定义异常的形式,但是并不能说明自定义异常的实际使用。

总结

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

推荐阅读更多精彩内容

  • 导语 学完异常的捕获及处理就懂的情书。 主要内容 异常的产生以及对于程序的影响 异常处理的格式 异常的处理流程(核...
    一个有故事的程序员阅读 4,337评论 4 4
  • 异常的产生 当遇到异常,执行到异常语句时,程序会中断执行,后面的也不会执行,出现异常。 处理异常(try...ca...
    嘉美伯爵阅读 368评论 0 0
  • 经常听到大家自暴自弃的说法,说我们缺乏想象力,没能创造出与国外一样优秀的成果来,纷纷的将孩子送外国外读书,似乎这样...
    如释笔记阅读 407评论 0 0
  • 失眠夜 磨牙声梦话声如同一场又一场宣战 很是让人烦躁
    J_Laughing阅读 228评论 0 0
  • 前阵子通过非常慎重的考虑,筛选出加入007最重要的理由——希望持续写作可以慢慢变得更聪明一点。 这一条理由其实是非...
    亲吻苍穹阅读 116评论 0 0