Java面试必知:异常

异常的体系结构

Java面试必知:异常

异常类

Throwable类 — 可抛出的

  • 是所有异常或者错误的顶层父类
  • 构造方法: Throwable(); Throwable(String message);
  • 常用方法
    • getMessage()–获取异常的错误信息
    • toString()–返回整体类型 + 异常的错误信息
    • printStackTrace()–打印异常栈信息,包括异常类名,调用的方法名,文件名,出错行数

Error类

  • 由于JVM或硬件引发的严重问题,无法通过程序代码捕获和处理,所有错误的类名都以Error结尾
    VirtualMachineError—虚拟机错误
    OutOfMemoryError—内存超出错误
    *Error—栈溢出错误

Exception–异常类

  • 需要程序捕获和处理
  • 运行时异常
    • ArithmeticException—算术异常
    • ClassCastException—类型转换异常
    • IndexOutOfBoundsException—下标越界异常
    • NullPointerException—空指针异常
  • 编译时异常
    • ClassNotFoundException—类没找到异常(JDBC部分)
    • InterruptedException—线程中断异常(线程部分)
    • IOException:
      • FileNotFoundException—文件没找到异常(IO部分)
      • SocketException–网络通信异常(网络部分)
    • SQLException—SQL异常(JDBC部分)
  • 运行时异常可以不做处理,但编译时异常必须进行处理.

异常的产生与处理

异常的默认处理

  • 程序一但出错,JVM就会创建一个相应的异常对象,如果没有处理语句,则会一直往上抛,直到main()方法,最终自动调用printStackTrace()方法打印异常栈的信息
  • 每调用一个方法,就会把当前方法进入方法栈,所以调用printStackTrace方法打印的时候,打印顺序和执行顺序正好是相反的

try—catch异常处理

  • 如果try块没有任何错误 则会跳过 catch块
  • 如果try块出现错误,Jvm会创建相应的异常对象,在catch块匹配相应的Exception类.catch块执行完成后,跳出try-catch块,继续执行后续语句. 如果没有匹配到,则会向上抛出,直到main()方法,最终调用printStackTrace方法
  • 异常捕获(catch)应该尽量细化,一个try可以匹配多个catch
  • catch块的排列顺序应该是子类在上,父类在下

throw和throws

  • throw关键字 用于手动抛出一个异常
  • throws用于声明本方法体可能抛出的异常
  • 如果一个方法的内部抛出一个运行时异常,则不强制要求进行处理
  • 如果一个方法的内部抛出一个编译时异常,则需要进行try-catch或者throws操作.(如果使用throws操作,则调用方也必须进行处理)
  • throw语句 后面的语句不会再执行

运行时异常和编译时异常的区别

  • 运行时异常因为是指运行之后,因为错误的数据而导致的异常.因此在编译时,不强制性对此异常进行处理
    ArithmeticException—算术异常
    ClassCastException—类型转换异常
    IndexOutOfBoundsException—下标越界异常
    NullPointerException—空指针异常
  • 编译时异常必须进行处理,要不编译不通过
    ClassNotFoundException—类没找到异常
    InterruptedException—中断异常
    IOException—IO异常
    SQLException—SQL异常(JDBC部分)

何时使用捕获异常,何时使用抛出异常

  1. 只抛不try
    方法的功能本身没有问题,由于调用者传递的参数导致的错误,抛给调用者处理.

  2. 只try不抛

    1. 在继承关系中,子类重写父类方法时,子类方法抛出的异常类型要小于或者等于父类方法抛出的异常类型,因此对于非父类异常及其子类,只能自行捕获并处理
    2. 如果抛出异常会影响用户交互,应该自行处理异常
  3. 实际开发中,两种方式可以结合使用,既在方法中捕获异常,以便记录日志信息,又将异常重新封装(一般把编译型异常转译运行时异常),再抛出给调用方去处理

finally块

  • finally块中的语句无论是否发生异常都会执行
  • finally不能单独存在,必须和try搭配使用
  • finally语句任何情况下都会执行,及时是前面有return语句,也会在return前先执行finally程序块.(除非遇到System.exit(0)强制退出)

自定义异常

  • 违反逻辑的错误,可以自己定义一个异常类
  • 捕获了一个编译时异常后,可以将异常对象重新包装成一个运行时异常对象,再次抛出给调用者.这样调用方对该异常的处理方式就变得灵活,既能知道发生了异常,又可以选择不对异常进行处理
  • 在分层的软件结构中,上层模块无需关心底层的异常细节,常见的做法是捕获原始异常,并将其转换为一个新的异常对象,再抛出给上层模块

异常处理的优化原则

  1. 异常是用来描述非正常情况,不要用来处理正常逻辑
  2. 养成良好的编码习惯,及时进行检查,避免出现运行时异常
  3. 避免庞大的try块
  4. 避免笼统的捕获异常或者笼统的抛出异常,尽量使异常具体化
  5. 不要在catch中忽略异常,应该进行及时的处理.如进行日志记录等
  6. 资源释放应该放在finally块中,保证无论是否抛出异常,都可以进行有效执行