当前位置: 首页 > 图灵资讯 > 技术篇> 说说异常(Exception)吧

说说异常(Exception)吧

来源:图灵教育
时间:2023-09-05 11:54:10

Java异常两万字详解,面试再也不怕被问! (qq.com)

Java的异常是Throwable包括两个子类的子类

  1. 程序本身可以捕获和处理异常。Exception 这种异常可分为两类:运行异常和编译异常。
    • RuntimeException 类及其子类,Java 编译器不会检查它。属于非受检异常。如果这种异常可能发生在程序中,"没有通过throws声明抛出它",也"它没有被try-catch语句捕捉到",还是会通过编译。例如,Nulllpointerexception空指针异常,Arrayindexoutboundexception数组下标越界异常,Clascascastexception类型转换异常,Aritheticexception算术异常。
    • 编译异常,Exception 中除 RuntimeException 子类以外的异常。属于检查异常。要么通过throws发表声明,要么通过try-catch捕获,否则不能通过编译。比如 IO相关异常,ClassNotFoundException(未发现指定类异常),SQLException。
  2. Error类别及其子类,代表程序中无法处理的错误,表明在应用程序运行过程中出现了严重的错误。JVM一般都有问题。这些错误是非检测异常和非代码性错误。当这些错误发生时,应用程序不应处理。我们不应该实现任何新的Error子类。eg. Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如 OutOfMemoryError:内存不足错误;StackOverflowError:栈溢出错误。
问:什么是异常检查,什么是非异常检查?

异常检查:编译器需要处理的异常。除外 RuntimeException 除了子类,其他的 Exception 异常属于异常检查。

非检测异常:编译器不检查,不需要处理异常,包括运行异常(RuntimeException极端子类)和错误(Error)。

问:throw和throws有什么区别?

throw关键字用于方法内部,只能用于抛出异常。用于抛出方法或代码块中的异常,可以抛出检查异常和非检查异常。

在方法声明中使用throws关键字,可以抛出多个异常列表,表示该方法可能抛出的异常列表。一种方法 throws 识别可能抛出的异常列表。调用该方法的方法必须包含可处理的异常代码,否则也应在方法签名中使用 throws 关键字声明相应的异常。

问:JVM是如何处理异常的?

如果在一种方法中出现异常,该方法将创建一个异常对象并将其转移给JVM。异常对象包括异常名称、异常描述和异常发生时应用程序的状态。创建异常对象并将其转移给JVM的过程称为抛出异常。

可能有一系列的调用方法,最后进入抛出异常的方法。调用这一系列方法的有序列表称为调用栈。

JVM将沿着调用堆栈查找是否有可以处理异常的代码。如果是这样,请调用异常处理代码。当JVM发现可以处理异常代码时,它会将异常传输给他。如果JVM没有找到可以处理异常的代码块,将异常转移到默认的异常处理器,打印异常信息并终止应用程序。

追问:try-catch-finally 如何使用?
  • try块:用于捕获异常。然后可以连接零或多个 catch 块,如果没有 catch 块,必须跟着一个 finally 块。
  • catch块:用于处理 try 捕获的异常。
  • finally 块:无论是捕获还是处理异常,finally 块中的句子将被执行。当 try 块或 catch 块中遇到 return 语句时,finally 在方法返回之前,将执行句块。
问:以下代码输出?
public static void main(String[] args) {    System.out.println(f(2));}public static int f(int value) {    try {        return value * value;    } finally {        if (value == 2) {            return 0;        }    }}

输出0,

当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 句子会被忽略。这是因为 try 语句中的 return 当返回值执行到本地变量时,返回值将首先暂时存在 finally 语句中的 return 之后,本地变量值变为 finally 语句中的 return 返回值。

追问:try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
public static int getInt() {    int a = 10;    try {        System.out.println(a / 0);        a = 20;    } catch (ArithmeticException e) {        a = 30;        return a;        /*         * return a 当程序执行到这一步时,这里不是returnnn a 而是 return 30;这种返回路径形成了         * 但是,它发现后面有finally,所以继续执行finally的内容,a=40         * 回到以前的路径,继续走returnn 30.返回路径形成后,这里的a不是a变量,而是常量30         */    } finally {        a = 40;    } return a;}// 执行结果:30
public static int getInt() {    int a = 10;    try {        System.out.println(a / 0);        a = 20;    } catch (ArithmeticException e) {        a = 30;        return a;    } finally {        a = 40;        //如果是这样,又形成了一条返回路径,因为只能通过一个return返回,所以直接返回40        return a;     }}// 执行结果:40

会执行,在 return 前执行。

在 finally 改变返回值的做法是不好的,因为如果有的话 finally try中的代码块 return 语句不会立即返回调用者,而是记录返回值待 finally 执行代码块后,将其返回给调用器,然后如果是 finally 修改后的返回值将返回修改后的值。

追问:finally 在什么情况下代码不会执行?
try {    System.out.println("Try to do something");    throw new RuntimeException("RuntimeException");} catch (Exception e) {    System.out.println("Catch Exception -> " + e.getMessage());    // 当前正在运行的Java虚拟机终止    System.exit(1);} finally {    System.out.println("Finally");}

输出:

Try to do somethingCatch Exception -> RuntimeException

finally情况如下 代码不会执行。

  1. 虚拟机终止运行
  2. 程序所在的线程死亡。
  3. 关闭 CPU。
追问:知道try-with-resources

为了实现资源的自动释放,所需的类别已经实现AutoCloseable接口。

private  static void tryWithResourceTest(){    try (Scanner scanner = new Scanner(new FileInputStream("c:/abc"),"UTF-8")){        // code    } catch (IOException e){        // handle exception    }}

try 当代码块退出时,它会自动调用 scanner.close 方法,和把 scanner.close 方法放在 finally 如果代码块不同, scanner.close 抛出异常,就会被抑制,抛出仍然是原始异常。

上一篇:

说说泛型吧

下一篇:

说说String吧