Java基础——异常处理

异常,说起来,就是一张图,5个关键字。

一张图

image.png

5个关键字

  • try
  • catch
  • finally
  • throw
  • throws

Java的异常捕获机制是怎么处理异常的?
要出捕获,要么抛出


一、异常

异常是程序运行过程中出现的错误。
Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的父类。

异常主要分类两类,一类是 Error,另一类是 Exception
Exception有两个子类,一个是 RuntimeException,另一种是 非运行时异常,比如IOException。

接下来就说说说上面出现的这几个东西

  • Throwable
    异常和错误的爹,错的都是他

  • Error
    Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
    就好像,你走路走着走着,前方的路塌了,你能怎么办,无计可施。

  • Exception
    Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。

    • 运行时异常 RuntimeException
      运行时异常都是RuntimeException类及其子类。叫运行时异常嘛,运行时发生的异常,RuntimeException是我们程序开发中需要重点处理的异常
      如NullPointerException、 IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引 起的,程序应该从逻辑角度尽可能避免这类异常的发生。
  • 非运行时异常/检查性异常/检查异常/编译异常
    (非运行时异常,叫法有点多)
    一个异常,如果不是运行异常,那么他就是 非运行时异常。
    比如如IOException、SQLException等以及用户自定义的Exception异常。这些异常在编译时就会报错,我们必须处理,想不处理都不行。

二、5个关键字

Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws。

我们先来看一下

    try{       
        //(尝试运行的)程序代码     
        }catch(异常类型 异常的变量名){       
            //异常处理代码     
        }
        // finally 不是必须的
        finally{       
            //异常发生,方法返回之前,总是要执行的代码     
        }
    }

1、try

try语句块,表示要尝试运行代码,try语句块中代码受异常监控,其中代码发生异常时,会抛出异常对象。

2、catch

  • catch语句块会捕获try代码块中发生的异常并在其代码块中做异常处理,catch语句带一个Throwable类型的参数,表示可捕获异常类型。
  • 当 try中出现异常时,catch会捕获到发生的异常,并和自己的异常类型匹配,若匹配,则执行catch块中代码,并将catch块参数指向所抛的异常对象。
  • catch语句可以有多个,用来匹配多个中的一个异常,一旦匹配上后,就不再尝试匹配别的catch块了。

通过异常对象可以获取异常发生时完整的 JVM堆栈信息,以及异常信息和异常发生的原因等。

3、finally

finally语句块是紧跟catch语句后的语句块,这个语句块总是会在方法返回前执行,而不管是否try语句块是否发生异常

比如我们tr……catch IO输入输出的异常,那么我们可以在finally里面把流给关闭。

目的是给程序一个补救的机会。这样做也体现了Java语言的健壮性。

示例代码1 运行时异常
我们先来看一段代码,用0做除数,会抛异常

public class ThrowableTest {
    public static void main(String[] args) {    
        int a = 3;
        int b = 0;
        // 0如果做除数会抛异常
        System.out.println("result: "+a/b);
    }
}

运行抛会异常

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at TrowTest.ThrowableTest.main(ThrowableTest.java:8)

这里抛出的异常是运行时异常,在编译的时候不会出现。必须我们程序员自己在编码做预防处理,比如用异常捕获机制try……catch
.
.
示例代码2 异常捕获机制

public class ThrowableTest {
    public static void main(String[] args) {    
        int a = 3;
        int b = 0;
        try {
            // 0如果做除数会抛异常
            System.out.println("result: " + a / b);
        } catch (Exception e) {
            System.out.println("捕获到异常: " + e.toString());
        }
    }
}

运行结果:

捕获到异常: java.lang.ArithmeticException: / by zero

异常被我们捕获了,程序没奔溃,正常运行。

.
.

try,catch和finally的使用注意点

  • 1、try、catch、finally三个语句块均不能单独使用
    三者可以组成

    • try...catch...finally、
    • try...catch、
    • try...finally
      三种结构。

    catch语句可以有一个或多个,finally语句最多一个。

  • 2、try、catch、finally三个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。

  • 3、多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch语句的顺序是由上到下。

throws

throws表示什么

  • 当一个方法参数列表之后throws Exception,用来声明方法可能会抛出某些异常,那么调用该方法的地方就必须try……catch捕获异常,否则编译不通过。

throws什么时候用呢

  • 如果一个方法中某些代码有可能造成某种异常,但是并不确定怎么处置,那么这个方法应该声明抛出异常,表示该方法不对这些异常进行处理,有调用者进行着。

  • 如果调用者也无法处理这些异常,那么应该继续抛出throws,如果一层层往上throws,那么这个异常会最终达到main方法,到了main就终止了,JVM肯定会让你处理,这样编译就可以通过了。
    (如果你异常一致背向上抛到了main方法,你main方法从语法上其实也可以也throws Exception,da你是这么做就没意义了,跑出来干嘛,一点意思都没有了,一旦异常就奔溃了)

  • 当方法的调用者无力处理该异常的时候,应该继续抛出,而不是随随便便在catch块中打印一下堆栈信息做个勉强处理。当然,有能力处理的应该及时处理。

throw

throw关键字是用于方法体内部(语句抛出),用来抛出一个Throwable类型的异常。

  • 如果我们在方法里面的语句throw一个异常,那么分两种情况
    • 1、在方法内部对应 throw 异常的语句我们进行try……catch,那么异常就会在当前方法被处理,这没什么问题。
    • 2、在方法内部对应 throw 异常的语句我们没有进行try……catch,那么在当前方法我们用throws Exception,不然抛出这个异常没人接,就不好了。
      (只throw,不try……catch也不throws特可以,但是这样没意思一点)
  • 如果throw的是自定义异常,那么就必须 内部捕获异常 或者 throw Exception

.
.

示例代码 throws

public class Test {
    static String abc = null;
    public static void main(String[] args) {
        try {// 因为show() throws Exception,所以调用者 try……catch,不然编译不通过
            show(abc);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void show(String s) throws Exception{
        //这句代码会引发 java.lang.NullPointerException
        s.toString(); 
        
    }
}

输出

java.lang.NullPointerException
    at TrowTest.Test.show(Test.java:14)
    at TrowTest.Test.main(Test.java:7)

如上,我们在show方法 throws Exceptionthrows Exception了,所以调用者就艺try……catch
.
.

代理示例 throw 出 运行时异常

public class ThrowableTest {
    public static void main(String[] args) {
        int a = 3;
        int b = 0;
        System.out.println("result:  "+divisionNum(a, b));
    }
    
    private static  int divisionNum(int n1,int n2){
        try {
            if (n2 == 0) {
                throw new ArithmeticException("在方法内的语句 throw 抛出运行时异常");
            } 
        } catch (Exception e) {
            System.out.println("捕获异常  "+e.toString());
        }
        return n1/n2;
    }
}

运行结果,运行失败抛异常

Exception in thread "main" 捕获异常  java.lang.ArithmeticException: 在方法内的语句 throw 抛出运行时异常
java.lang.ArithmeticException: / by zero
    at TrowTest.ThrowableTest.divisionNum(ThrowableTest.java:18)
    at TrowTest.ThrowableTest.main(ThrowableTest.java:7)


.
.

自定义异常

ToMinException

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

.
.
ToMaxException

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

.
.
Test

public class Test {
    
    public static void main(String[] args) {
        Test test = new Test();
        try {
            test.simpleAdd10to20(8, 17);
        } catch (ToMinException e) {
            e.printStackTrace();
            System.out.println("捕获到的异常信息  toString()   :"+e.toString());
            System.out.println("捕获到的异常信息:getMessage()  "+e.getMessage());
        }catch(ToMaxException e){
            e.printStackTrace();
            System.out.println("捕获到的异常信息  toString()   :"+e.toString());
            System.out.println("捕获到的异常信息:getMessage()  "+e.getMessage());
        }
        
        //getMessage() //输出异常的信息 
        // printStackTrace() //输出导致异常更为详细的信息 
        
    }
    
    // 这个方法只允许大于10,和小于20的数字,我们违反规则的数抛异常(仅为演示)
    private int simpleAdd10to20(int a,int b) throws ToMinException,ToMaxException{
        if(a>10 || b>10){
            throw new ToMinException("不能有小于10 的参数");
        }
        
        if(a>20 || b>20){
            throw new ToMaxException("不能有大于20 的参数");
        }
        return a+b;
    }
}

输出:

TrowTest.ToMinException: 不能有小于10 的参数
    at TrowTest.Test.simpleAdd10to20(Test.java:27)
    at TrowTest.Test.main(Test.java:8)
捕获到的异常信息  toString()   :TrowTest.ToMinException: 不能有小于10 的参数
捕获到的异常信息:getMessage()  不能有小于10 的参数

以上演示完自定义异常了。

最后我们顺便说一下几个关于异常的方法:
e.printStackTrace();
是打印异常的堆栈信息,指明错误原因,其实当发生异常时,通常要处理异常,这是编程的好习惯,所以e.printStackTrace()可以方便你调试程序!

e.toString()
具体哪个异常类哪个方法,具体异常提示是什么

e.getMessage()
最简要的异常内容提示

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

推荐阅读更多精彩内容

  • “简单不先于复杂,而是在复杂之后.” —— Alan Perlis Java异常 异常指不期而至的各种状况,如:文...
    白衬衫少年阅读 270评论 0 0
  • Java异常类型 所有异常类型都是Throwable的子类,Throwable把异常分成两个不同分支的子类Erro...
    予别她阅读 915评论 0 2
  • 初识异常(Exception) 比如我们在取数组里面的某个值得时候,经常会出现定义的取值范围超过了数组的大小,那么...
    iDaniel阅读 1,863评论 1 2
  • 音乐慢慢流淌,下午茶的时光,精致而富有情调的咖啡厅,就只有怡一个人坐着,侍者都在吧台上窃窃私语,时不时传来他们的调...
    落落大慌阅读 211评论 0 0
  • 落叶,枯黄了这个季节的天。 雨雾延绵,或倾诉着别离的忧怨。 秋雁归到远,不曾召唤也不曾留恋。 我愿与它同去! 倘若...
    勒巴阅读 189评论 1 4