1.finally 块中的代码什么时候被执行?
-
finally 块的作用就是为了保证无论出现什么情况,finally 块里的代码一定会被执行。
-
如果 try-finally 或者 catch-finally 中都有 return,那么 finally 块中的 return 将会覆盖别处的 return 语句,最终返回到调用者那里的是 finally 中 return 的值。
public int test() { try { int a = 10/0; } catch(Exception e) { return 1; } finally { return 2; } } ## 输出 2
2.finally 是不是一定会被执行到?
-
不一定。下面列举两种执行不到的情况:
(1)当程序进入 try 块之前就出现异常时,会直接结束,不会执行 finally 块中的代码;
(2)当程序在 try 块中强制退出时也不会去执行 finally 块中的代码,比如在 try 块中执行 exit 方法。
3. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
-
会。程序在执行到 return 时会首先将返回值存储在一个指定的位置,其次去执行 finally 块,最后再返回。因此,对基本数据类型,在 finally 块中改变 return 的值没有任何影响,直接覆盖掉;而对引用类型是有影响的,返回的是在 finally 对 前面 return 语句返回对象的修改值。
4. try-catch-finally 中那个部分可以省略?
-
catch 和 finally可以省略其中一个,但必须保留其中一个。
5. Error 和 Exception 的区别?
Error 类和 Exception 类的父类都是 Throwable 类。主要区别如下:
-
Error 类: 一般是指与虚拟机相关的问题,如:系统崩溃、虚拟机错误、内存空间不足、方法调用栈溢出等。这类错误将会导致应用程序中断,仅靠程序本身无法恢复和预防;
-
Exception 类:分为运行时异常和受检查(编译时)的异常。
6. 运行时异常与编译时异常有何异同?
-
运行时异常:如:空指针异常、指定的类找不到、数组越界、方法传递参数错误、数据类型转换错误。可以编译通过,但是一运行就停止了,程序不会自己处理;
-
编译时异常:除了运行时异常,其他都是编译时异常,要么用 try … catch… 捕获,要么用 throws 声明抛出,交给父类处理。
7. throw 和 throws 的区别?
-
throw:在方法体内部,表示抛出异常,由方法体内部的语句处理;throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例;
-
throws:在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理;表示出现异常的可能性,并不一定会发生这种异常。
8.常见的异常类有哪些?
-
ArithmeticException
:用于描述算术运算错误,比如除数为零。 -
NullPointerException
:用于描述当对一个空对象引用执行操作时发生的错误。 -
ArrayIndexOutOfBoundsException
:用于描述数组索引越界的错误。 -
IllegalArgumentException
:用于描述传递给方法的参数不合法或无效的错误。 -
NumberFormatException
:用于描述将字符串转换为数值类型时发生的格式错误。 -
FileNotFoundException
:用于描述尝试打开文件时未找到指定文件的错误。 -
IOException
:用于描述输入/输出相关的错误,比如读写文件、网络通信等操作出错。 -
ClassNotFoundException
:用于描述尝试加载类时找不到相应的类的错误。 -
InterruptedException
:用于描述线程在等待、睡眠或被中断时被打断的错误。 -
SQLException
:用于描述与数据库操作相关的错误。
9.主线程可以捕获到子线程的异常吗?
-
主线程是无法直接捕获到子线程抛出的异常的。
-
当在子线程中发生未捕获的异常时,该异常会导致子线程终止,并且不会影响主线程的执行。
-
可以通过一些技术手段来获取并处理子线程中的异常
如:
使用线程池:如果使用线程池来管理线程,那么可以通过实现 Thread.UncaughtExceptionHandler
接口并将其设置为线程池的默认异常处理器来捕获和处理子线程中的异常。
javaCopy CodeThread.setDefaultUncaughtExceptionHandler((t, e) -> { // 处理子线程中的异常 }); ExecutorService executor = Executors.newFixedThreadPool(5); executor.execute(() -> { // 子线程的代码 }); executor.shutdown();