开发笔记之详解JAVA异常的前世今生

我原本是个快乐的iOS开发者, 总是会看到一张图片:


抛出异常

我就在想crash就crash了呗, 弄这么多学名干嘛, 还抛出异常. 后来经过我对JAVA的研究我发现我的想法被啪啪打脸, 那叫一个左右开弓.
( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)
还是我太naive, 而今天, 就要详述一下异常这个东西.


我们要确立一个概念, 那就是: 什么是异常机制.

异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。

当你明白异常机制是怎么回事的时候,异常处理的流程你也不难接受.

当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出,java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交到catch块中的代码,然后继续往下执行程序,try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块,在所有的finally块代码被执行和当前线程的所属的ThreadGroup的uncaughtException方法被调用后,遇到异常的当前线程被中止。

用代码表示就是:

        try {
            System.out.println("寻找到try关键字");
        } catch (Exception e){
            e.printStackTrace();
            System.out.println("捕获异常");
        } finally {
            System.out.println("无论走try还是走catch, finally中的代码都会被执行");
        }

java.lang.Throwable

既然要说明白异常的前世今生就要先说一说这些异常的前世, java.lang.Throwable是 Java 中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 JVM 或者 Java throw 语句来抛出, 换言之, 所有的异常都是从他这出来的, 他是所有异常的祖宗类.
而且, 类似的, 只有此类或其子类之一才可以是 catch 子句中的参数类型.


常见的异常之间的关系

由图可见, 他有两个子类, 这两个子类就是区别开了两种不同的异常.


第一种.java.lang.Error

Error是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题, 这个问题有多严重? 十分严重, 不可恢复的错误, 这种情况下的程序只能终止运行, 但是要注意一点的是, 编译器不会检查Error是不是被处理, 程序中也不用捕获Error类型的异常, 一般情况下, 程序中也是绝对不应该抛出这种异常的, 但是一旦出现Error必须修改源代码.

第二种.java.lang. Exception

Exception是由JVM发出的异常, 他的异常类型包括两种, 一种是RuntimeException, 另外一种是Checked Exception异常或者说是(记成)非RuntimeException类型的异常也可.

RuntimeException类型的异常是很特殊的, 他是一种Unchecked Exception, 编译器不会检查程序是不是处理了RuntimeException, 在程序中也不去捕获RuntimeException类型的异常, 也不会再方法体中抛出RuntimeException. RuntimeException类型的异常出现的时候表示程序中出现了逻辑编程错误, 作为程序员应该找出错误并且修改.

Checked Exception异常, 或者说是非RuntimeException类型的异常, 是Exception异常种类中除了RuntimeException异常就是他了, 而JAVA规定了所有的Checked Exception异常都要处理, 编译器也会检查这种异常是否存在, 要么抛出, 要么try catch捕获, 处理, 否则将不能通过编译.


出现异常怎么办

对于异常, 真正有用的是意向的对象类型, 而不是异常对象本身, 每一种异常对象都有着自己的含义, 老规矩, 为了便于理解, 上代码!

    public static double div(int a, int b){
        return a / b;
    }
    // 然后调用
    div(4, 0);

显而易见的, 我们犯了一个很基础的错误, 那就是拿一个整数去除以0, 当然, 我们亲爱的JAVA不会惯着我们.

又抛出异常

我们来看一下抛出的异常信息.

异常信息

在这里我们会看到几处有意思的东西.

  1. java.lang.ArithmeticException 这个东西好像是类?
  2. by zero 我好像是除以0了.
  3. at com.company.Main.div(Main.java:69)
    at com.company.Main.main(Main.java:28) 这两行.

我们首先来看看java.lang.ArithmeticException, 这个类的意思是当出现异常的运算条件时,抛出此异常。就比如说我们所做的,一个整数“除以零”时,抛出此类的一个实例.

然后再看 by zero, 的确是除以0了, 没毛病.

最后再看最后这两行东西, div和main好像是你的两个方法, Main是不是主入口呢? 你看了一下 69 行和 28 行

   return a/b; // 69行
   div(4, 0); // 28行

大呼神奇.
现在你能看懂异常了.


自定义异常

你以为看懂异常就结束了吗? naive, 你不但要会看, 你还要会写, 编程瞬息万变, 你怎么能确定JAVA就考虑到所有你可能出错的情况呢? 所以, 当JAVA内置的异常都不能明确的说明异常情况的时候,需要创建自己的异常.
但是你需要注意的是, 唯一有用的就是类型名这个信息,所以不要在异常类的设计上花费精力, 他只是去给你提供一个信息的.
还是上代码来的清楚, 请看.

class Computer {
    public String getStatus() {
        return status;
    }

    public void setStatus(String status) throws DownException, EnterWaterException {
        this.status = status;
        if (status.equals("进水")){
            throw new EnterWaterException("进水了, 烧了");
        } else if (status.equals("摔了")){
            throw new DownException("摔了, 有钱了");
        }
    }
    private  String status;
}

class DownException extends RuntimeException{
    public DownException(String message){
        super(message);
    }
}

class EnterWaterException extends RuntimeException{
    public EnterWaterException(String message){
        super(message);
    }
}

你可以清晰的看到我新建了两个异常, 并把他放入一个叫做Computer的类中, 并让 setStatus方法接着向上抛出异常.

        Computer computer = new Computer();
        try {
            computer.setStatus("进水");
        } catch (EnterWaterException e){
            e.printStackTrace();
        } catch (DownException e){
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }

然后我try catch了异常. 来看一下输出的结果.

异常信息

怎么样, 是不是结果显而易见, 但是这里有几点需要注意一下, 并且要记住.

  1. 对于应该在声明方法抛出异常还是在方法中捕获异常, 我们应该遵守一个原则, 捕捉并处理哪些知道如何处理的异常,而传递哪些不知道如何处理的异常
  2. 多个异常捕获, 异常对象存在父子关系是, 要求父类型的异常, 写在子类的下面
  3. 多个异常可以合并在一个catch中 catch(Exception e), 但是为了看着清晰我没有这么做.
  4. throws 是声明这个方法的调用存在异常情况, 调用者需采取捕获处理或继续向外抛的操作才能通过编译
  5. 当代码出现问题时, JVM会创建一个异常对象并抛个调用者
  6. 调用者接收到异常之后不能处理, 继续往上抛直到抛给JVM, 最终将异常信息输出到控制台
最后输出到控制台

这里是一些常见的异常, 方便与在大家在抛出异常的时候来对照:

ArithmeticException——由于除数为0引起的异常;
ArrayStoreException——由于数组存储空间不够引起的异常;
ClassCastException—一当把一个对象归为某个类,但实际上此对象并不是由这个类 创建的,也不是其子类创建的,则会引起异常;
IllegalMonitorStateException——监控器状态出错引起的异常;
NegativeArraySizeException—一数组长度是负数,则产生异常;
NullPointerException—一程序试图访问一个空的数组中的元素或访问空的对象中的 方法或变量时产生异常;
OutofMemoryException——用new语句创建对象时,如系统无法为其分配内存空 间则产生异常;
SecurityException——由于访问了不应访问的指针,使安全性出问题而引起异常;
IndexOutOfBoundsExcention——由于数组下标越界或字符串访问越界引起异常;
IOException——由于文件未找到、未打开或者I/O操作不能进行而引起异常;
ClassNotFoundException——未找到指定名字的类或接口引起异常;
CloneNotSupportedException——一程序中的一个对象引用Object类的clone方法,但 此对象并没有连接Cloneable接口,从而引起异常;
InterruptedException—一当一个线程处于等待状态时,另一个线程中断此线程,从 而引起异常;
NoSuchMethodException一所调用的方法未找到,引起异常;
IllegalAccessExcePtion—一试图访问一个非public方法;
StringIndexOutOfBoundsException——访问字符串序号越界,引起异常;
ArrayIdexOutOfBoundsException—一访问数组元素下标越界,引起异常;
NumberFormatException——字符的UTF代码数据格式有错引起异常;
IllegalThreadException—一线程调用某个方法而所处状态不适当,引起异常;
FileNotFoundException——未找到指定文件引起异常;
EOFException——未完成输入操作即遇文件结束引起异常。


怎么样, 大家是不是对于异常都已经有了自己的理解了呢, 希望大家要达道下图的水平.


解决异常

我们作为程序员, 每天都在想的无非就是我怎么把代码敲得更牛逼, 更美观, 而我一直认为知识, 见解, 经验的分享和学习是自我进行学习的一个重要的途径, 所以, 知识的分享总会增值, 非常期待与各位看官切磋想法, 交流心得.

个人其他文章:
个人编程想法心得(不定期更新)
开发笔记之详述JAVA构造函数和代码块本身及其执行细节
开发笔记之冒泡排序, 选择排序, 折半查找
iOS开发笔记-基于AFNetworking 3.0的登录 注册
开发笔记之JAVA String StringBuffer StringBuilder
开发笔记之JAVA ArrayList 和 LinkedList

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

推荐阅读更多精彩内容

  • 通俗编程——白话JAVA异常机制 - 代码之道,编程之法 - 博客频道 - CSDN.NEThttp://blog...
    葡萄喃喃呓语阅读 3,161评论 0 25
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,572评论 18 399
  • 六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代...
    Executing阅读 1,316评论 0 6
  • Java异常 异常指不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行...
    java部落阅读 3,099评论 1 13
  • 人啊,总是善变的。留下那些深浅不一的伤疤,还在提醒着,早已不在他心尖,又何必去追。 “分手吧!” 冰冷的屏幕上发来...
    素人小子阅读 252评论 2 2