Java面试笔记之异常处理
针对Java面试题中的异常处理部分,特别地写一篇博文来总结一下。不说废话,先提出问题,再给出解决方案,再总结。走起!
1. 面试问题
基础知识:
Q1:什么是异常?什么是错误?异常和错误的区别是什么?
Q2:Java中的异常类的继承结构
Q3:异常中的运行异常和检查异常
Q4:try-catch-finally块的使用
Q5:自定义异常类的使用
Q6: throw和throws的区别
高级知识:
Q1: finally块什么时候执行?finally块一定会执行吗?通常在finally块执行什么?finally块执行内存优化的技巧和原因
Q2: 子类方法不应该抛出比父类方法更大范围的异常
Q3:try-catch块的使用注意事项
2. 问题解答
基础知识:
A1:
异常指的是在Java程序运行的过程中发生的一些非正常的情况或者错误,针对非正常的情况或者错误的发生,Java可以通过try-catch-finally块来捕获异常从而处理异常,使得异常发生时,程序可以通过处理异常从而恢复原来的正常状态,而不至于停止运行。错误则是在JVM层面上的错误,Java程序中不能通过try-catch-finally块来捕捉错误,也就不能使得错误发生时,通过必要的手段处理恢复正常,错误发生时程序只能停止。
A2:Java异常类的继承结构大概如下
A3:
运行时异常通常编译器不会强制对其捕获或者处理,都是通过JVM来处理
检查异常通常编译器会强制对其捕获或者处理,发生在编译阶段
对比的表格内容如下:
类别 | 发生阶段 | 是否强制 | 包含异常 | ||
运行异常 |
发生在程序运行时 |
否 |
NullPointerException(空指针异常) |
ArrayStoreException(数据存储异常) |
ClassCastException(类型转换异常) |
|
|
|
IndexOutofBoundExcpetion(数组越界异常) |
BufferOverflowException(缓冲区溢出异常) |
ArithmeticException(算法异常) |
|
|
|
|
|
|
检查异常 |
发生编译时 |
是 |
IOException(IO读写异常) |
SQLEception(SQL异常) |
|
A4:
try{
监控的代码块
}
catch()
{
异常处理的代码块
}
finally{
回收资源,内存优化的代码块
}
A5:
新建一个自定义异常类来继承exception类
public class ZeroException extends Exception {
private String str;
public void PrintStr()
{
System.out.println("throws ZeroException by"+str);
}
@Override
public String toString() {
return super.toString();
}
public void setStr(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
然后在程序中抛出这个类,并使用try-catch处理
public class MemoryLeak {
public static void main(String[] args)
{
try{
int c= divied(2,0);
System.out.println("c is "+c);
} catch (ZeroException e) {
e.setStr("异常!被除数不能为0!分母不能为0!");
e.PrintStr();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static int divied(int x,int y ) throws ZeroException{
if (y==0) {
throw new ZeroException();
}
else
{
System.out.println("print divided by "+x/y);
return x/y;
}
}
}
A6:
- throw通常出现在函数体内,表示要抛出这个异常。如果在某个函数声明时throws了异常,那么有需要通过try-catch块来捕获和处理异常,否则也会报错
- 如果某个函数内部用throw抛出了异常,那么在方法声明中一定要配套使用throws,否则会报错
- .throws通常出现在函数声明的位置,表示这个方法可能要抛出这个异常
高级知识
A1:针对finally的深入了解,我们可以看这一篇文章
https://blog.csdn.net/qq_39135287/article/details/78455525
A2:子类方法不应该抛出比父类方法更大的异常的原因时,由于Java的设计原则,我们默认将父类方法应该充分考虑到运行环境的险恶程度,所以需要最大的限度地来捕获和处理异常。如果子类抛出了比父类更大的范围的异常,那么子类处理了异常,父类应该怎么办呢?如果子类的抛出的异常由父类来处理,那么抛出更大的异常时,由于父类并没有定义其相关的异常处理,就无法处理子类的异常
A3:
1. 尽量使用try-catch-finally块来处理异常,在finally块中应该尽可能的回收内存资源
2. 尽量减少try监控的代码块
3. 应该先用专业的异常来处理,再用exception来处理
4. 在catch语句块中,不要简单的抛出异常,更要尽可能的处理异常
5. 出现异常后,应当保证项目不能就此终止,要把异常造成的影响降到最低