Java异常类简介以及throws,try,catch,throw,finally的区别

时间:2022-12-15 16:43:23

1.异常简介

在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性。

Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java
异常处理的重要子类,各自都包含大量子类。

  • ① Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时
    JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM
    不再有继续执行操作所需的内存资源时,将出现
    OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual
    MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在
    Java中,错误通过Error的子类描述。
  • ②  Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类
    RuntimeException。RuntimeException 类及其子类表示“JVM
    常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、
    ArithmeticException)和 ArrayIndexOutOfBoundException。

注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。
通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。

  • ① 可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。
    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
  • ② 不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。

    Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。

  • ① 运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
    运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

  • ② 非运行时异常 (编译异常):是
    RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不
    能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
    注意:进行异常捕获时所有父类异常的catch块都应该排在子类异常catch块的后面(先处理小异常,再处理大异常)。

2.Java中2种异常处理机制:

  • ① 在发生异常的地方直接处理。
  • ② 将异常抛给调用者,让调用者处理。

3. finally:

程序在try里打开了一些物理资源(如数据库连接、网络连接等),这些物理资源必须显示回收。因为java的垃圾回收机制不会回收任何物理资源,只能回收 堆内存中对象所占用的内存。为了保证一定能回收try中打开的物理资源,异常处理机制提供了finally块,不管是否出现异常,finally块总会被 执行。异常处理语法结构:只有try块是必须的,catch和finally是可选的,但至少出现其中之一,catch可有多个。
以下情形,finally将不会被执行

  • ① finally块中发生异常
  • ② 程序所在线程死亡
  • ③ 在前面的代码中用了System.exit()
  • ④ 关闭cpu

注意:一旦finally中使用了return或throw语句,将会导致try块、catch块中的return、throw语句失效。
当java程序执行try块、catch块时遇到了return或throw语句,这两个语句会导致方法立即结束,所以系统并不会立即执行者两个语句,
而是去寻找是否有finally块,如果没有,程序立即执行return或throw语句,方法终止;如果有finally,系统立即执行finall
块,只有当finally块执行完成后系统才跳回来执行try、Catch块里的return、throw,如果finally里也使用了return或
throw等导致方法终止的语句,则finally块已经终止了方法,系统将不会跳回执行try、catch块里的任何代码。

4.throws:

throws只能在方法签名中使用,可以声明抛出多个异常类,以逗号隔开。
使用throws的情况:

  • ① 当前方法不知道应该如何处理这种类型的异常。
  • ② 该异常应该由上一级调用者处理。抛出的异常将讲给JVM处理。处理方法是:打印异常跟踪栈信息并终止程序运行,这就是程序一道异常后自动结束的原因。

注意:使用throws抛出异常时有一个限制,就是方法重写时:子类方法中声明抛出的异常类型应该是父类抛出异常类型的子类或相等。

使用Checked异常至少存在两大不便之处:

  • ① 对于程序中Checked异常,java要求必须显式的捕获并处理该异常或显式声明抛出,这就增加了编程的复杂度。
  • ② 如果在方法中显式声明抛出Checked异常麻将会导致方法签名与异常耦合,如果方法是重写父类的方法,则该方法能抛出的异常还受被重写方法所抛出的异常限制。

5.throw

java允许程序自行抛出异常,由throw来完成。其抛出的不是异常类,而是一个异常实例,每次只能抛出一个异常实例。
如果throw抛出的异常时checked异常,则该throw语句要么处于try块里,显式捕获该异常,要么放在一个带有throws声明的方法 中;如果throw语句抛出的异常时runtime异常,则该语句无须放在try块里或带throws抛出的方法中,程序可以显式使用 try…catch来捕获,并处理异常,也可以完全不理会该异常,把该异常交给该方法调用者处理。

6.throws与throw的区别

  • ① throws是用来声明一个方法可能抛出的所有异常信息。
    throw则是指抛出的一个具体的异常类型。通常在一个方法(类)的声明处通过throws声明方法(类)可能抛出的异常信息,而在方法(类)内部通过throw声明一个具体的异常信息。
  • ② throws通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法。
    throw则需要用户自己捕获相关的异常,而后在对其进行相关包装,最后再将包装后的异常信息抛出。
  • ③ 对异常处理方式不同:throws对异常不处理,谁调用谁处理,throws的Exception的取值范围要大于方法内部异常的最大范围,而cathch的范围又要大于throws的Exception的范围;hrow
    主动抛出自定义异常类对象. throws抛出的是类,throw抛出的是对象。
  • ④ throw用在程序中明确表示这里抛出一个异常。throws用在方法声明的地方,表示这个方法可能会抛出某异常。throw用来抛出实际的异常,
    后面要跟一个异常对象(实例), 是一个实际的语句。使用throws是来说明当前的函数会抛出一个异常。

7.自定义异常类

需要继承Exception基类,如希望自定义Runtime异常则需继承RuntimeException基类,定义异常时要提供两种构造器,无参的和带一个字符串的,这字符串作为该异常对象的详细说明,即getMessage()方法的返回值。

8.总结:

  • ① 处理异常,对异常采用合适的修补,然后绕过异常发生的地方继续执行;或者用别的数据进行计算以代替期望的方法返回值;或者提示用户重新操作等,总之,对于checked异常,程序应该尽量采用修复。
  • ② 重新抛出异常,把当前运行环境下能做的事情尽量做完,然后进行异常转译,把异常包装成当前层的异常,重新抛出给上层调用者。
    -