Java SE 之异常篇

目录

 

一、异常概念

二、异常体系结构

三、异常处理机制

四、checked 异常和 unchecked 异常

六、自定义异常用法

 


一、异常概念

在Java程序运行期间出现非正常的情况,导致操作流程的非正常终止或程序崩溃。

二、异常体系结构

 

Throwable 是所有错误和异常的父类,只有这个类或实现了这个类的对象才能使用 throws 或 throw 关键字进行抛出。同样,只有继承了这个类才可以在 try {} catch(XxxException e) {} 中进行异常的捕获。

三、异常处理机制

如果遇到了异常情况,我们可以怎样进行处理呢?

3.1 抛出异常

如果遇到了异常情况而又不想进行处理,我们可以在方法首部声明抛出一个 checked 异常,如下,是 Scanner 类的一个构造器声明 :

抛出异常有两种方式:第一种就像上面那样,使用 throws 关键字在方法首部声明异常;第二种就是使用 throw 子句的方式在方法内部抛出异常。如下所示(本例纯粹是演示 throw 子句的使用方法):

那么,throw 和 throws 的区别是什么呢。

如果是 JDK 中定义的异常,可以直接使用 throws 在方法首部声明抛出,所有已定义的异常由系统自动抛出;

而用户自定义的异常,必须借助 throw 语句来进行抛出,异常的触发条件由用户自行判断。所抛出的异常也必须在方法首部进行声明。

3.2 捕获异常

如果某个异常发生时没有在任何地方进行捕获,程序就会终止运行,并打印异常信息。
要想捕获异常,必须设置 try/catch 语句块。 如下所示:

try {
    doSomething...
} catch (ExceptionType e) {
    // 处理异常信息
}

如果在 try 语句块中抛出了在 catch 中声明的异常类型,那么程序就会跳过 try 块中的剩余代码进入到 catch 语句块中执行其语句。

在一个 try 语句中可以对应有多个 catch 语句块进行捕获多个异常类型。

捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。

3.3 补充 - finally 子句

无论是否有异常被捕获,finally 子句都会被执行。

try {
    doSomething...
} catch (Exception e) {
    // 处理异常
} finally {
    // 无论是否有异常捕获,finally 子句一定会被执行
}

finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。

如果是 JDK7 及以上,可以使用 try-with-resources 的方式。

四、checked 异常和 unchecked 异常

4.1 定义

Java API 中对 checked 异常定义如下:

The class Exception and any subclasses that are not also subclasses of RuntimeException are checked exceptions. Checked exceptions need to be declared in a method or constructor's throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.

Exception 类和非 RuntimeException 类的子类都是 checked 异常。如果检查异常可以由方法或构造函数的执行抛出并在方法或构造函数边界之外传播,则需要在方法或构造函数的 throws 子句中声明它们。

unchecked 异常即 checked 异常之外的 Error 类和 RuntimeException 类(运行时)异常。

4.2 异常处理

一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制(Error),要么就应该尽量避免发生(RuntimeException)。

如《Java开发手册-华山版》中异常处理第 1 条:

Java 类库中定义的可以通过预检查方式规避的 RuntimeException 异常不应该通过 catch 的方式来处理,比如:NullPointerException,IndexOutOfBoundsException 等等。

说明:无法通过预检查的异常除外,比如,在解析字符串形式的数字时,可能存在数字格式错误,不得不通过 catch NumberFormatException 来实现。

正例:if (obj != null) {...}

反例:try { obj.method(); } catch (NullPointerException e) {…}

五、Trowable 详解

每一个 trowable 在创建时都包含有其线程当时的堆栈快照。

其有四个 public 构造方法和一个 protected 构造方法:

/**
 * fillInStackTrace方法用来初始化它的异常轨迹的数组 
 */
 public Throwable() {
    fillInStackTrace();
}

public Throwable(String message) {
    fillInStackTrace();
    // 初始化异常描述信息  
    detailMessage = message;
}

/**
* cause:引起此异常的原因对象
*/
public Throwable(String message, Throwable cause) {
    fillInStackTrace();
    // 初始化异常描述信息  
    detailMessage = message;
    this.cause = cause;
}

public Throwable(Throwable cause) {
    fillInStackTrace();
    detailMessage = (cause==null ? null : cause.toString());
    this.cause = cause;
}

/**
* enableSuppression 是否启用抑制异常,如禁止,则getSuppressed方法返回长度为0的数组
* writableStackTrace 是否启用堆栈跟踪
*/
protected Throwable(String message, Throwable cause,
                    boolean enableSuppression,
                    boolean writableStackTrace) {
    if (writableStackTrace) {
        fillInStackTrace();
    } else {
        stackTrace = null;
    }
    detailMessage = message;
    this.cause = cause;
    if (!enableSuppression)
        suppressedExceptions = null;
}

六、自定义异常用法

在具体的业务场景中,我们可能需要包含业务含义的自定义异常。这时,只需要 定义一个继承与 Exception 类 或 Exception 子类的类。自定义异常类的父类构造方法如上 Throwable 所述。如下例,定义一个ServiceException:

public class ServiceException extends Exception {
    public ServiceException() {
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值