前言:
写了两周的博客了,深的浅的都有,总有人问我写博客有什么用?能出书吗?写的太浅有人看吗?对找工作有什么帮助吗?不想争辩,也不愿把自己说的多么高大上,分享本身是一件简单的小事,但是能给我带来快乐,我享受别人看过我博客之后有种觉得有收获那种感觉,就这么简单。还有那些害怕写博客被别人质疑太浅的,其实大可不必,总有一些人掌握的知识没有你多,也许你的一句话就解决了他们的疑问。言归正传,今天给大家带来Java异常体系。
1、Java异常体系结构图
继承Exception的异常
继承RuntimeException的异常
然后:继承Exception的异常应该出现在这种情况里,即我的代码极有可能出现这种异常,因为我无法考虑到所有环境,因此我抛出给调用方根据自己的环境进行对应处理。继承RuntimeException的异常应该出现在此种环境里,即我的代码出现这种异常的可能性不是特别大,但是还是有出现的可能,而在出现这种异常的时候我能够给调用方以足够的提示信息告知他发生了什么。
3、异常捕获机制
3.1、catch捕获范围
从第一个catch开始到最后一个catch形成捕获队列,按照队列的顺序谁先捕获到就归谁处理。这个过程要考虑多态的问题,由于Exception是许多异常类的父类,因而如果处在队列前面,后面的队列的声明就没有意义了。
public static int bMethod() {
try {
return cMethod(true);
} catch (EException e) { //第一个捕获
e.printStackTrace();
} catch (Exception e) { //第一个没捕获到,第二个来捕获
e.printStackTrace();
} finally {
return 1;
}
}
3.2、finally的执行问题
finally的中文意思是最终,也就是段try catch finally代码的try catch该执行的都执行完之后最终要执行finally里的代码。简单起见可以把try catch finally看成一个代码块。
为了更好的解释finally运行机制,我们先了解一下虚拟机栈帧。
虚拟机栈帧
我们知道,每个线程都有一个自己的栈空间,实际上,当方法执行的时候JVM会把方法制作成栈帧压入到操作栈中,每个方法都对应着一个栈帧,当前执行的栈帧总是位于栈顶。
栈帧包含局部变量表、操作数栈、动态连接、方法返回地址。这里的方法返回地址实际上是在方法遇到ret指令之后返回值存放的位置的地址,也就是说返回值并没有直接返回给方法的调用者,而是中间又多了一步将返回值存放到栈的某一个位置。在真正把返回值交给上层调用者之前,如果遇到break、continue、return、抛出异常等情况JVM会清除栈中的返回值
例子1,返回100
public static int method1() {
int k = 0;
try {
k = 1;
//返回的k=1首先存储到栈中的返回值位置,如果顺利完成就把该位置的值返回,如果遇到特殊指令如break、continue、return、抛异常就清除
return k;
} catch (Exception e) {
e.printStackTrace();
} finally {
//清除原来的返回值,把100放到返回值的位置上,如果顺利结束就返回,否则清除
return 100;
}
}
例子2,返回100
public static int method2() {
int k = 1;
while (true) {
try {
return k;
} catch (Exception e) {
e.printStackTrace();
} finally {
//遇到break,返回值位置的值被清除
break;
}
}
k=100;
return k;
}
例子3,说明finally不是一定会执行
public static int method1() {
int k = 1;
//此处抛异常或者try和catch里调用system.exit()方法finally就不会执行。
Integer.parseInt(null);
try {
return k;
} catch (Exception e) {
e.printStackTrace();
} finally {
return k;
}
}
总结
其实日常开发我们遇到最多的就是NPE问题,NPE问题即是小问题又是破坏健壮性的大问题,我们应该更好的防范一下。我刷leetcode和进行一些日常开发总结了一些经验,供大家参考下:
1、入参是对象的时候应该对入参进行判空操作
2、调用的其他人写的方法返回的是对象的时候应该对该对象进行判空操作
3、调用数据库或者远程调用的返回值应该进行判空操作
4、保证调用者为已知对象。str1.equals(str2)方法,str1应该是已知对象,str2可以为空;String.valueOf()和Integer/Long/Double.toString()返回值相同使用前者
5、自己写的方法尽量不要返回空值