Java基础之异常

什么是异常?

 异常是在程序运行过程中发生的,会打断程序正常执行的事件。异常可以分为两大类Error和Exception。它们都是继承于java.lang.Throwable类。Exception有多个子类,其中RuntimeException和IOException是常用的两个子类。

异常层次结构图

 由层次结构图可以看出异常主要由Error和Exception组成,那么Error和Exception它们之间有什么区别呢?
Error:属于系统类的错误,是我们无法无法给予适当的处理的。
Exception:异常在捕获之后可以针对性的使用代码进行处理,确保程序能正常运行。
"如果出现 RuntimeException,那么就一定是你的问题"是一条想当有道理的规则。因为这有可能是程序编写的逻辑问题等。

如何处理异常?
  • 抛出异常
     抛出异常通常有三种方式:
     1)在程序中抛出异常。

e.g.

package exception;

public class ThrowException {

    public static void main(String[] args) {
        int a= 10,b=0;
        int c ;
        if(b==0) {
            throw new ArithmeticException("被除数为0 ,程序出错了");
        }else {
            c = a/b;
        }
        System.out.println(c);

    }

}

 抛出异常的时候,throw关键字所抛出的是异常类的实例对象,
 所以在程序中抛出异常的格式为: throw new 异常对象;

 程序运行结果为:

Exception in thread "main" java.lang.ArithmeticException: 被除数为0 ,程序出错了
    at exception.ThrowException.main(ThrowException.java:17)

 2)在指定方法中抛出异常
e.g.

package exception;

public class ThrowException {

        public void divisionTest(int a, int b) throws ArithmeticException{
            int c = a/b;
            System.out.println(c);
        }
        public static void main(String[] args) {
            ThrowException test = new ThrowException();
            test.divisionTest(10, 0);
        }
}


 如果方法内的程序代码块可能会发生异常,但是方法内有没有使用任何代码块来捕捉这些异常,则必须在申明方法中指明可能发生的异常,以便让调用此方法的程序做好准备来捕捉异常。

 在指定方法中抛出异常其格式为:methodName(参数) throws 异常类。如果一个方法可能抛出多个异常,则用","分隔多个异常,其语法格式为:methodName(参数) throws 异常类1,异常类2,异常类3,....

 3)系统自动抛异常
e.g.

package exception;

public class ThrowException {
        public static void main(String[] args) {
            int a= 10,b=0;
            int c ;
            c = a/b;
            System.out.println(c);
        }
}

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at exception.ThrowException.main(ThrowException.java:19)

 系统自动抛出了异常,并且显示了异常类型,出错类型。

那么throw、throws抛出异常有什么区别呢?
  throw 语句必须写在函数中,且throw 抛出的是一个具体的异常类型,在执行throw 语句的地方就是一个异常抛出点,抛出的异常在方法体内进行处理。
 throws用于在方法中抛出一个或多个异常,这些异常将被抛给方法的调用者。调用者要在方法中捕获异常,如果不捕获异常则必须在方法中使用throws继续将异常抛出,直到异常被处理。

  • 捕获异常
     如果某个异常发生的时候没有任何地方进行捕获,那么程序就会终止执行,并在控制台上打印相应的异常信息。其中包括异常类型和堆栈内容。那么要想捕获一个异常,必须设置try/catch语句块。try/catch语句也可以有多个catch子句用于捕获多个异常。当多catch分别捕获异常的时候,最上面的catch应该捕获的是子类的异常,最后的一个catch,一定捕获的需要捕获的异常的最后那个父类。
    其格式为:

try{
 可能出现异常的代码块;
} catch(ExceptionType1 e){
 处理异常1;
}catch(ExceptionType2 e){
 处理异常2;
}catch(ExceptionType3 e){
 处理异常3;
}finally{
 一定会被执行的代码块;
}

  • 如果在try语句块中的某一段代码抛出了异常,且catch子句中申明了该异常,则程序将跳过不执行抛出异常代码之后的其他代码,将去执行catch子句中处理异常的代码。执行的内容为try{}catch(){}finally{}
  • 如果try语句块中抛出了catch子句中没有申明的异常,那么程序将一直执行try语句块中的所有语句,直到有异常被抛出为止。
  • 如果try语句块中没有抛出异常,程序将会跳过catch子句。执行的内容为try{}finally{}

注:

  1. try内声明的变量,类似于局部变量,出了tyr{}语句,就不能被调用了。
  2. catch语句内部是对异常对象的处理:getMessage(); printStackTrace();来获取程序的出错信息。getClass().getName();来获取异常对象的实际类型。
    e.g.
package exception;

public class ThrowException {
        public static void main(String[] args) {
            int a= 10,b=0;
            int c = 0 ;
            try{
                if(b==0) {
                    throw new ArithmeticException("被除数为0 ,程序出错了");
                }else {
                    c = a/b;
                }
            }catch (ArithmeticException e) {
                e.printStackTrace();
            }finally {
                System.out.println(c);
            }
    
        }

运行结果

java.lang.ArithmeticException: 被除数为0 ,程序出错了
    at exception.ThrowException.main(ThrowException.java:17)
0

 该段代码的运行结果为0 ,这表明在try语句中抛出了catch子句中申明了的异常,在遇到异常时,直接跳过了出异常之后的代码,执行了catch子句中的内容。并且不管try语句块有没有抛出异常最后都一定会执行finally子句的。

在catch子句中可以捕获多个异常,捕获多个异常时异常的变量会被隐含为final变量,其书写格式为:

try{
 可能出现异常的代码块;
} catch(ExceptionType1 | ExceptionType2 e){
 处理异常;
}catch(ExceptionType3 e){
 处理异常;
}finally{
 一定会被执行的代码块;
}

值得注意的是当异常不存在子类关系的时候才能够这样书写,它不仅能够让你的代码看起来更简洁,也会更高效。

final、finally、finalize的区别?

final是修饰符(断子绝孙符),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。并且不可被修改,被声明为final的变量必须在声明时给定初值,也不能override。

public static final String str = "123"

finally是在异常处理时与try-catch-finally配套使用。不管try语句块有没有抛出异常,如果有finally子句的话,子句中的内容都将会被执行。

finalize是方法名。是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。

如果try {}里有一个 return 语句,那么 finally {}里的 语句 会不会被 执行,什么时候被执行,在 return 前还是后呢?
package exception;

public class finallyTest {
    
    
    public int finalRturn(int a, int b) {
        
        try {
            if(a%b == 0) {
                System.out.println("b能被a整除!");
            }else {
                throw new ArithmeticException("b不能被a整除!");
            }
            return 1;
            
        }catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("这是捕获的异常");
            return 2;
            
        }finally {
            System.out.println("这是不管有没有异常都要被执行的");
            return 3;
        }
        
    }

    public static void main(String[] args) {
        finallyTest finallyTest = new finallyTest();
        int result = finallyTest.finalRturn(10, 4);
        System.out.println(result);
    }

}

运行结果:

java.lang.ArithmeticException: b不能被a整除!
    at exception.finallyTest.finalRturn(finallyTest.java:13)
    at exception.finallyTest.main(finallyTest.java:33)
这是捕获的异常
这是不管有没有异常都要被执行的
3

 由于将a赋值为10,b赋值为4,所以a不能整除b,就会抛出异常 ” b不能被a整除!“,同时执行catch语句打印出 ” 这是捕获的异常 “,然后执行finally语句打印 ” 这是不管有没有异常都要被执行的 “ 并且返回return值,由于在程序中遇到return 则程序将会结束,所以只返回了finally中的return 值,但是如果在finally中没有return值,那么程序将会返回到catch中再去将catch中的return值返回。

带资源的try语句

 带资源的try语句的最简单表现形式为

try(Resource res = ......; Resource1 res1 = ......){
 work with res;
}

 try语句中可以指定多个资源,当try语句块退出时,不管try语句块正常退出或者存在异常,都会自动调用res.close();语句,就像使用了finally语句一样。只要需要关闭资源就尽可能的使用带资源的try语句块,这样可以简化你的代码。

自定义异常

 为了处理各种各样的异常,java 可以通过继承的方式来自定义异常,由于所有可处理的异常类都继承于Exception类,所以自定义异常以必须继承这个类。

class 异常名称 extends Exception{
   代码块;
}

e.g.

package exception;

public class customException {

    public static void main(String[] args) {
        try {
            throw new defaultException("这是一个自定义异常");
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

}

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

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

推荐阅读更多精彩内容