【从基础学 Java】异常机制

初识

代码的世界和现实世界同样,不会一路顺风,起码不会像咱们想象中的那么顺利。写代码的是人,人的思惟存在局限性,这种局限性,体如今代码中,就是漏洞。假若一段程序在生产环境中崩溃,势必让人十分恼火。这种让人头大的状况就是异常的一种。html

Java 是这样定义异常的:java

异常指的是,那些在程序运行过程当中,中断正常的指令流程的事件。

实际上,异常还会在如下场景中发生:程序员

  • 用户输入错误,如:输入不符合程序预期
  • 设备错误,如:网线断开链接
  • 物理限制,如:内存不足

而咱们并不但愿程序由于上述状况挂掉,而是但愿程序可以在遇到异常时,巧妙地处理以后,继续运行下去。oracle

所幸,Java 提供了一套机制,用于在程序程序出错(出现异常)时,进行:编码

  • 报告错误
  • 保存工做结果
  • 让用户以更完善的方式退出程序

亦即:异常处理机制。顾名思义,该机制用于对程序运行中不正常的状况进行处理。
简单来讲,Java 中的异常处理是:当异常发生时,运行时系统逆着方法的调用栈(call stack)去寻找可以处理这种异常的东西。spa

以一个把字符串转换成整数的方法为例:设计

public Integer stringToNumber(String strToFormat){
    Integer targetNum;
    try{
        targetNum = new Integer(strToFormat);
    }catch(NumberFormatException e){
        targetNum = DEFAULT_NUM;
    }
    return targetNum;
}

在上述代码中,当 strToFormat 不能转化成一个整形数时,就转化成一个默认的值。NumberFormatException 发生时,方法当即终止。控制权被交由 catch 代码块,也就是异常处理器(exception hanlder)。代码虽然简单,却包含了 Java 异常处理的通常步骤。code

异常分类

在 Java 中,全部的异常派生于 Throwable 接口。这些异常,又被分为 ErrorException。这两类异常,又衍生了一些子类。下面的图片,描述了 Java 的异常体系图:orm

Java 异常体系图

不过,咱们应当把精力放在 RuntimeException 上,由于“全部的运行时异常,都是程序员的问题”。这类异常,又被叫作未检查异常,一般交由 JVM 处理。相对应的,那些咱们知道可能会出现问题、,被叫作已检查的异常。这类异常须要开发者手动向上级抛出,直到 JVM 级别,或者在调用方法时使用 try-catch 处理。htm

通常来讲,在写一个方法时,要尽量声明全部已检查异常,经过内部逻辑控制,避免未检查(运行时)异常。

异常捕获

在编码过程当中,若是方法的检查异常被精心设计,那么咱们只管抛出异常便可。可是,一旦调用方法的地方没有对这种可能出现的异常进行处理,那么程序就会终止。因此,要对异常进行捕获操做,正如以前的字符串转数字的方法同样。

根据经验,程序中应该捕获那些知道如何处理的异常,把“职责”外的异常,交给方法的调用者去处理。下面是一个异常捕获流程的示例代码:

modifier returnType someMethod(type1 param1, type2 param2) throws Exception1, Exceptio2{
    
        try{
            ① // 某些操做
            return returnType value;
        }catch(Exceptionx | Exceptiony e){
            ② // 处理异常
        }catch(Excpetion1 e1){
            ③ throw new Excption1(e1);
        }catch(Exception e2){
            ④ throw e2;
        }finally{
            ⑤ // 一些操做
            return returnType mockValue;
        }
        
}

在上述代码中,① 中进行操做,捕获了 Exeptionx 或者 Exceptiony 时,② 进行异常处理;捕获了 Exception1 时, ③ 把该异常包装;捕获了 Exception 2 时,④ 直接抛出异常;不管有无异常发生,⑤ 都会执行。

上面的代码还有一个问题,就是 finally 代码中包含返回值。有如下规则:

  • try 代码块中包含 return 语句,finally 语句中的代码也会被执行;若 finally 中也包含 return 语句,则会替代 try 中的语句

使用异常的技巧

  • 不要过度细分异常,能用一个 try 块处理的尽可能用一个,而后按层次捕获异常,下面的代码是被建议的:
try{
    // 某些操做
}catch(SomeException1 e1){
    // 异常 1 的处理
}catch(SomeException2 e2){
    // 异常 2 的处理
}
  • 适当地转化异常,如:能够把一个 NumberFormatException 转化成自定义的异常
  • 遇到异常状况,能够更加严格一点。如:抛出 EmptyStackException 比 NullPointerException 更加语义化
  • 学会把异常传递,即:「早抛出,晚捕获」
相关文章
相关标签/搜索