JAVA异常概述

异常概述

对程序员来说,需要尽可能的预知所有可能发生的错误情况并且做出相应处理,但是很多时候无法穷举出所有的错误,例如一个只能输入int类型的输入框,我们需要对double、String、Char等等类型作出判断。JAV的异常机制可以让程序一次性处理所有的错误;当程序出现意外情况时,系统会自动生成一个Exception对象通知程序,使得业务处理代码和错误处理代码分离开来;

异常处理机制

try{
    
}
catch (Exception e){
    
}

异常类的继承体系

上面代码中的Exception是所有异常类的父类,每个catch块都是专门用于处理该异常类及其子类的异常实例;

当JAVA运行时环境接收到异常对象后,会依次判断该异常对象是否是catch中定义的异常类或其子类实例,如果是,就调用该catch块,否则接着往下比较;一般只会有一个catch块被调用;

JAVA把所有的非正常情况分为两种:异常和错误,他们都继承Throwable父类。Error错误一般是与虚拟机相关的错误,这种错误无法恢复或无法捕捉,通常应用程序无法处理这些错误;

多异常捕获

try{

}
catch (IndexOutOfBoundsException|ArithmeticException|NumberFormatException e){

}

捕获多种异常时,异常变量(上面的e)有隐式的final修饰,无法对其进行重新赋值;

访问异常信息

Java程序可以通过访问catch块后的异常形参来获得异常对象的相关信息,当Java运行时决定调用某个catch块来处理该异常对象时,会将异常对象赋给catch块后的异常参数,程序即可通过该参数来获得异常的相关信息。

所有异常对象都包含了如下几种常用方法:

getMessage():返回该异常的详细描述字符串。

printStackTrace():将该异常的跟踪栈信息输出到标准错误输出。

printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流。

getStackTrace:返回该异常的跟踪栈信息。

使用finally回收资源

try中的代码有时候会打开一些需要显式回收的物理资源,这时候回收代码如果写在try里,当try中抛出异常时回收代码没法执行,写在catch里正常运行时又没法回收,因此JAVA提供了finally块,finally块总会被执行;

JAVA9的自动关闭资源的try语句

JAVA9允许try后面紧跟一对圆括号,括号中可以声明、初始化资源,这些资源会在try中语句执行完后自动回收;

为了保证try语句能正常关闭资源,这些资源实现类必须实现AutoCloseable或Closeable接口;

Checked异常和Runtime异常体系

Java的异常被分为两大类:Checked异常和Runtime异常(运行时异常)。所有RuntimeException类及其子类实例被称为Runtime异常;不是RuntimeException类及其子类的异常实例则称为Checked异常。

只有Java语言提供了Checked异常,其他语言都没有提供Checked异常。Java认为Checked异常都是可以被处理(修复)的异常,所以Java程序必须显式处理Checked异常。

对于Checked异常的处理方式有两种:

(1)当前方法明确知道如何处理该异常,程序应该使用try…catch块来捕获该异常,然后对应的catch块中修补该异常

(2)当前方法不知道如何处理这种异常,应该在定义该方法时声明抛出该异常。

Runtime异常则更加灵活,Runtime异常无须显式声明抛出,如果程序需要捕捉Runtime异常,也可以使用try…catch块来捕捉Runtime异常。
当使用throw语句自行抛出异常,如果throw语句抛出的异常是Checked异常,则该throw语句要么处于try块里,显式捕获该异常,要么放在一个带throws声明的方法中,即把该异常交给该方法的调用者处理;也就是说当出现了(不管是自行抛出的,还是系统抛出的)Checked异常,就要想办法去处理它,不能不理会它,要么显式地在try…catch块里捕获,处理它;要么把它放在一个带throws声明的方法中,把异常交给该方法的调用者处理。

如果throw语句抛出的异常是Runtime异常,则该语句无须放在try块里,也无须放在带throws声明抛出的方法中;程序既可以显式使用try…catch来捕获,并处理异常,也可以完全不处理该异常,把异常交给该方法调用者处理。

使用throws声明抛出异常

使用throws声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理,如果main方法也不知道怎么处理,也能使用throws把异常抛给JVM处理,JVM处理方法为:打印异常跟踪栈信息,并且中止程序运行。

抛出异常的几种情况:

1.没有使用try…catch捕获异常,也没有throws声明,当不存在ssss.txt时,程序报错,提示“必须对其捕获或者声明“;

public static void main(String args[]){
    FileInputStream fis = new FileInputStream("ssss.txt");
}

2.使用了try…catch捕获异常,当不存在ssss.txt时,程序不会报错,控制台输出“异常”;

public static void main(String args[]){
    try{
        FileInputStream fis = new FileInputStream("ssss.txt");
    }
    catch(Exception e){
        System.out.println("异常");
    }
}

3.使用throws抛出异常,系统会打印异常的跟踪栈信息

public static void main(String args[]) throws IOException{ 
    FileInputStream fis = new FileInputStream("ssss.txt");
}

对于带throws声明的方法在进行重写时,子类方法声明的异常必须与父类相同或者是其子类。

抛出异常和处理异常

抛出异常指的是这部分代码自己不处理异常,把异常丢给调用自己的上级,上级如果也不能处理就会接着上抛;处理异常指的是代码自己处理这部分异常;

抛出异常的两种方式

一、显示地通过throws向上级抛出异常
抛出原因:当程序中可能出现异常,但又不想在本级代码中处理时,这时候就会向上一级抛出异常。
抛出作用:向上级抛出异常可以通知上级,我这里可能会出现异常,并且可以告诉上级我这里可能出现哪些异常,需要上级处理或上级再向上上级抛出…,不管上级是否进行异常信息处理,其都要显示的进行(处理或向上上级抛出)。

二、隐式地抛出异常(即在没有语法错误但可能出现逻辑或其他异常的地方)
在程序代码中,当没有语法错误,但可能出现逻辑或其他异常的时候(例如:在数据库引起的异常),正常情况下程序是可以正常运行的,但当出现例外时就会报异常,这种异常很多时候我们并没有人为显示的去对异常进行处理,而是代码中隐地逐层向上级抛出,最终在JDK底层进行异常处理。
PS:对于隐式抛出的异常,在需要处理异常的中间环节方法中可以直接try、catch捕捉异常并进行处理。

使用throw抛出异常

有时候,对于某种情况是否是异常,需要由应用的业务需求决定,在某些情况下是异常,有些情况下不是异常;例如下五子棋,当用户输入的下棋位置已经有棋子了,这时该引发异常;当该位置没有棋子的时候,应该不引发异常。

用户可以通过throw自己定义异常,当new出异常实例并且抛出后,系统中断当前的执行流,并且开始执行catch里面的语句;如以下代码会输出“异常”:

public static void main(String args[]){
    try{
        int a =0;
        throw new Exception("异常");
    }
    catch(Exception e){
        System.out.println(e.getMessage());
    }
}

之前处理异常的方式有两种:

1.在出现异常的方法内捕获并且处理异常,方法的调用者不能捕获到这个异常;

2.抛出异常给方法的调用者去处理;

我们也可以在catch中定义throw,使得当前的方法能够处理这个异常,方法的调用者也能捕获到这个异常,两者共同处理异常;

异常链模式

对于底层代码的异常信息,把其直接向上传递暴露给上层的用户层是不负责任的行为,一般的做法是:程序捕获原始异常并且保存,然后抛出一个新的业务异常,新的异常中包含了对用户的提示信息,这也被称为“异常链模式”。

所有的Throwable子类在构造器里都可以接收一个cause对象作为参数,这个cause就用来表示原始异常,这样可以把原始异常传递给新的异常,使得即使在当前位置创建并且抛出了新的异常,也能通过这个异常链追踪到异常最初的位置。

public static void main(String args[]) throws SQLException {
    try{
        int a =0;
    }
    catch(Exception e){
        throw new SQLException(e);
    }
}

T

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值