JavaSE 基础学习之四 —— 异常的处理

接上篇《JavaSE 基础学习之三 —— Java 的继承与接口》


四. Java 核心专题 —— 异常处理

1. 两种类型的异常

  • 运行时异常 (RuntimeException):不处理也能通过编译,jvm 会帮助处理,也可以自行处理;
  • 其他异常:对于其他异常,如果不处理程序就不能通过编译,必须自己处理;

注:
所有的异常产生之后,都是一个类的实例对象,而且这些异常全部继承于 Exception;java 中对所有的异常都进行了细致分类,每种异常都有一个具体的类。

2. 异常处理的关键字

(1) try... catch...

  • try 后面可以有多个 catch;
  • 所有的异常都是 Exception 的子类
  • 多个 catch 的时候,父类的异常一定要写在子类的后面
  • Exception 可以认为是万能异常;
  • 常用 Exception 的方法:
    • getMessage(): 返回此 throwable 的详细消息字符串;
    • toString():返回此 throwable 的简短描述。
    • printStackTrace():打印异常的堆栈,将此 throwable 及其追踪输出至标准错误流;

(2) finally

finally 关键字后无论有没有异常,最终都要执行的操作;

例:

public class Demo1 {
    public static void main(String[] args) {
        try {
            int a = Integer.parseInt(args[0]);
            int b = Integer.parseInt(args[1]);
            System.out.println(a/b);
        } catch (ArrayIndexOutOfBoundsException e) {
            // TODO: handle exception
            System.out.println("数组下标越界");
        } catch (ArithmeticException e) {
            System.out.println("除数不能为 0");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println(e);
            System.out.println("其他异常");
        } finally {
            System.out.println("无论有没有异常,最终都要执行的操作");
        }
    }
}

(3) throw

throw 关键字表示在某种情况下,我们自己手动抛出的异常实例

:定义一个 Person 类,对其年龄进行设置,如果年龄超过 120,则认为出现错误,手动抛出异常。

public class Person {
    private int age = 10;
    public int getAge() {
        return age;
    }

    public void setAge(int age) throws Exception{
        try {
            if(age < 0 || age > 120) {
                throw new Exception("年龄有误");
            } else {
                this.age = age;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果运行了程序 setAge(130),则会抛出“年龄有误”的异常。

(4) throws

throws 关键字在一个方法的方法签名后面使用,用处在于通过编译,告诉使用者一旦调用了当前方法,可能出现处理哪些异常,这样可以令使用者尽量的回避异常;当你的方法里抛出了 checked 异常,如你不 catch,代表你当时不处理(不想处理或没条件处理),但你必须得通过"throws那个异常"告诉系统说,这儿有个问题,我现在不处理,将来一定别人要处理,否则执行到它,系统会"不优雅"的崩溃。
举个例子,工兵张三发现了地雷,假如他处理完就完事儿了。但是他发现了地雷,自己却没带齐工具,没法处理,他必须做个标记,说这儿有一个地雷,别的工兵将来一定要处理,否则将来有人踩上去会爆炸。
注意:throws只是标记,并没处理,程序执行到那里,系统还是会崩溃!

public class Person1 {
    private int age;
    // throws 异常,通知此处代码有问题
    public void setAge(int age) throws Exception{
        if(age < 0 || age > 120)
            throw new Exception("年龄有误!");
        this.age = age;
        
    }
    public int getAge() {
        return age;
    }
}

3. 自定义异常

项目中,我们可以通过创建一个类继承 jdk 提供的异常类 (RunTimeException 或 Exception),自定义的实现一个异常类。

自定义异常的创建有利有弊:优点如下:

  • 工作过程中,项目是分模块或者分功能开发的,基本不会你一个人开发一整个项目,使用自定义异常类就统一了对外异常展示的方式
  • 有时候我们遇到某些校验或者问题时,需要直接结束掉当前的请求,这时便可以通过抛出自定义异常来结束。例如,如果你项目中使用了SpringMVC比较新的版本的话有控制器增强,可以通过@ControllerAdvice注解写一个控制器增强类来拦截自定义的异常并响应给前端相应的信息;
  • 系统中有些错误是符合Java语法的,但不符合我们项目的业务逻辑,使用自定义异常可以在我们项目中某些特殊的业务逻辑时抛出异常。例如对于性别,"中性".equals(sex),性别等于中性时我们要抛出异常,而Java是不会有这种异常的;
  • 使用自定义异常继承相关的异常来抛出处理后的异常信息可以隐藏底层的异常,这样更安全,异常信息也更加直观。自定义异常可以抛出我们自己想要抛出的信息,可以通过抛出的信息区分异常发生的位置,根据异常名我们就可以知道哪里有异常,根据异常提示信息进行程序修改。例如,空指针异常NullPointException,我们可以抛出信息为“xxx为空”定位异常位置,而不用输出堆栈信息。

自定义异常的缺点主要在于,发现异常、抛出异常以及处理异常的工作必须靠编程人员在代码中利用异常处理机制自己完成。这样就相应的增加了一些开发成本和工作量,所以项目没必要的话,也不一定非得要用上自定义异常,要能够自己去权衡。

关于自定义异常,可以参考《Java异常之自定义异常》的博客。

4. 关于异常的编程建议

建议:

  1. 自己抛出的异常必须要填写详细的描述信息,便于问题定位;
    • 例如:throw new IOException("Writing data error! Data: " + data.toString());
  2. 在程序中,选择使用异常处理还是错误返回码处理,应该根据是否有利于程序结构来确定,且不能将异常和错误码混合使用。通常情况下推荐异常处理
  3. 记录异常时,不要只保存 exception.getMessage(),一般可以通过日志工具记录完整的异常堆栈信息;
  4. 一个方法不应该抛出太多类型的异常。如果确实有很多异常类型,首先应该考虑用异常来进行区别。通常来说 throws / exception 子句标明的异常最多不要超过三个;
  5. 异常捕获尽量不要直接捕获 catch(Exception ex),应该把异常细分处理,设计更加合理的异常处理分支;
  6. public 类型的底层方法需要对输入参数进行判断,如果参数不合法,应该主动抛出 RuntimeException;

强烈建议

  1. 在调用的最高层,必须处理所有的异常;
  2. 如果捕获了异常,然后抛出新的异常,则必须将原异常的信息全部包含在新的异常中;
  3. 系统非正常运行产生的异常捕获之后,如果不对该异常进行处理,必须记录日志;
  4. 对于多个异常的额情况,必须对应多个 catch 分别处理,禁止使用一个 catch 处理多个异常。如下例所示:
public void sample() {
    try {
        // 某个抛出异常块
    }
    // 处理异常种类 1
    catch (IllegalStateException illEx) {
        log.wirte(illEx.printStackTrace());
        throw illex;
    }
    // 处理异常种类 2
    catch (SQLException SQLEx) {
        log.write(SQLEx.printStackTrace());
        throw SQLEx;
    }
    finally {
        // 释放资源
    }
}

接下篇《JavaSE 基础学习之五 —— IO 操作》

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

推荐阅读更多精彩内容

  • 引言 在程序运行过程中(注意是运行阶段,程序可以通过编译),如果JVM检测出一个不可能执行的操作,就会出现运行时错...
    Steven1997阅读 2,414评论 1 6
  • 八、深入理解java异常处理机制 引子try…catch…finally恐怕是大家再熟悉不过的语句了, 你的答案是...
    壹点零阅读 1,537评论 0 0
  • 住宿 重庆市区住宿的地方还是很多,但是还是推荐住在解放碑几个地铁站附近。因为这里交通便利,去到重庆的各个区域都较为...
    coooder阅读 298评论 0 0
  • 人生两境界: 一个知道,一个知足。 知道,让人活得明白; 知足,让人活得平淡。 人生不要被安逸控制, 决定你成功的...
    认识我你不亏阅读 321评论 0 0
  • 如何喜爱上你现在的工作?通过下面这14步就能找到答案。 1、写下你所在企业的愿景、使命。 2、在上面的内容中圈选出...
    嘉语嘉话阅读 229评论 0 0