异常

异常


概念

  1. 异常:有异于常态,和正常情况不一样,有错误出现,阻止当前方法或作用域。22
  2. 异常处理:将出现的异常提示给编程人员与用户,使原本将要中断的程序继续运行或者退出。并且能够保存数据和释放资源。

异常体系结构

所有异常都继承于Throwable类,其下有两大子类:

  1. Error类:错误,一般编程人员不太接触,如虚拟机错误、线程死锁。硬伤:使程序崩溃

  2. Exception类:异常,编码、环境、用户输入等问题,其子类主要有:

    • 非检查异常(运行时异常RuntimeException):【由java虚拟机自动捕获】如空指针NullPointer、越界ArrayIndexOutofBounds、错误类型转换ClassCast、算数异常Arithmetic等
    • 检查异常CheckException:【需要手动添加捕获和处理语句】文件异常IO等
    异常_第1张图片

异常处理


try-catch(多catch块)-finally

  1. try块:负责捕获异常,一旦try中发现异常,程序的控制权将被移交给catch块中的异常处理程序。【try语句块不可以独立存在,必须与 catch 或者 finally 块同存】

  2. catch块:如何处理?比如发出警告:提示、检查配置、网络连接,记录错误等。执行完catch块之后程序跳出catch块,继续执行后面的代码。

    编写catch块的注意事项:多个catch块处理的异常类,要按照先catch子类后catch父类的处理方式,因为会【就近处理】异常(由上自下)。

    异常_第2张图片
  3. finally:最终执行的代码,用于关闭和释放资源等

  4. return在try-catch-finally中:

    • 不管有木有出现异常,finally块中代码都会执行;
    • 当try和catch中有return时,finally仍然会执行;
    • finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的;
    • finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
  5. e.printStackTrace()可以输出异常信息

  6. -1为抛出异常的习惯写法

  7. 如果方法中try,catch,finally中没有返回语句,则会调用这三个语句块之外的return结果

  8. finally块无论如何,不管前面是正常还是异常,都要执行。

  9. finally 在try中的return之后 在返回主调函数之前执行。

Java中的异常抛出与自定义异常


两个重要的关键字:throw和throws

  1. throws的异常列表可以是抛出一条异常,也可以是抛出多条异常,每个类型的异常中间用逗号隔开

  2. 方法体中调用会抛出异常的方法或者是先抛出一个异常:用throw new Exception()

    throw写在方法体里,表示“抛出异常”这个动作

  3. 当某个方法调用到会抛出异常的方法,就必须调用try catch语句块来尝试处理异常

  4. 当调用者不知道或者不必处理异常时,就继续声明将抛出异常,给更上一层调用者处理

    异常抛出。

    左下角为可以处理异常的情况,可以捕获异常。

    右下角为divide不能处理异常时,抛出异常交由上级处理。

    异常_第3张图片

自定义异常

尽管Java提供了大量种类的异常,我们在实际使用时还会用到自定义异常:

自定义异常:要么继承于意思相近的异常,要么继承于所有异常类的基类Exception,必须是Exception或其子类。

class 自定义异常类 extends 异常类型{

}

异常链


Java中的异常链:将捕获的异常包装成新的异常,然后在新的异常中添加对原始异常的引用,再把这个新的异常抛出。就像是链式反应一样,一个导致一个。

这个想法是指一个方法应该抛出定义在相同的抽象层次上的异常,(将所有捕获到的异常包装为新的异常类,即定义在相同的抽象层次上抛出)但不会丢弃更低层次的信息。

实现异常链功能的两种基本写法:

public class chainTest {

    /**
    * @param args
    * Test1抛出喝大了异常
    * Test2调用test1捕获了喝大了异常,并且包装成运行时异常,继续抛出
    * main方法中调用test2尝试捕获test2方法抛出的异常
    */
public static void main(String[] args) {
    try{ 
        chainTest ct=new chainTest();
        ct.Test2();
    }catch(Exception e){
    e.printStackTrace();
    }
}

public void Test1()throws DrunkException{
    throw new DrunkException("喝车别开酒");

}

public void Test2(){
    try{
        Test1();
    }catch( DrunkException e){
        RuntimeException rte=new RuntimeException(e);
        //rte.initCause(e);
        e.printStackTrace();
        throw rte;
        }
    }
}

实际应用的经验与总结

  1. 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
  2. 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
  3. 对于不确定的代码,也可以加上try-catch,处理潜在的异常
  4. 尽量去处理异常,切记只是简单的调用printStackTrace()去打印
  5. 具体如何处理异常,要根据不同的业务需求和异常类型去决定
  6. 尽量添加finally语句块去释放占用的资源
  7. finally语句中一般不放break,return,continue!!!

你可能感兴趣的:(异常)