先上图
Java中所有的异常类都是继承于
Throwable
的,表示可以抛出的对象。Error
(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。比如:内存溢出什么的。Exception
(异常):与Error
不同,表示程序可以处理的错误。RuntimeException
:虽然写的是运行时异常,但是这里面提到的全部异常都是运行时发生了,这个名字其实不是很好。RuntimeException
表示的是程序逻辑出现错误,导致的。IOException
:指一些IO
方面的异常?(感觉也不是很准确)
需要注意的是
Error
和RuntimeException
都是未检查异常,也就是说不需要使用try...catch
来进行捕获。但是IOException
属于检查型异常是必须使用try...catch
来进行捕获或者将其抛出到外层调用者函数。
举个栗子
public class TTestException {
public void a() throws MyException {
throw new MyException();
}
public void b(){
try {
throw new MyException();
} catch (MyException e) {
e.printStackTrace();
}
}
public void c(){
String s = null;
System.out.println(s.length());
}
public static void main(String[] args) {
TTestException tTestException = new TTestException();
try {
tTestException.a();
} catch (MyException e) {
e.printStackTrace();
}
tTestException.b();
System.out.println("After b() before c()");
tTestException.c();
System.out.println("After c()");
}
}
这个例子里面a
和b
都会抛出检查型异常,但是a
是把异常再次向调用者抛出,b
是直接在函数内部就进行处理了。
再观察外层调用会抛出检查型异常的情况,调用a
的时候是必须对其进行处理的,要不就是try...catch
或者就是再次向外抛出,这里就应该明白一个道理就是一个检查型异常是必须在程序的某个层次中进行处理的,既然程序中进行了处理,那么这个检查型异常是不会导致程序停止的
,调用b
函数的时候,因为b
内部已经进行了处理,那么就可以正常的调用。
再来看看调用c
的情况,因为字符串s
是null,所以尝试获得一个length
的时候,是会发生空指针异常的,但是这个空指针异常又和上面的MyException
不同,空指针异常是个非检查型异常
,Java没有规定必须处理,可以处理,也可以不处理。
如果不进行处理,那么一但抛出这个异常,就是Java就会认为是程序逻辑有问题,从而停止这个正在运行的程序,所以在调用c
之后的打印函数,是不会打印出来东西的。但是为了保证程序不会因为这种逻辑异常不会停止,也进行try...catch
的话,那么也就是处理了这个异常,就不会被强制停止线程的运行。
关于自定义异常
自定义异常一般是继承于Exception
类。可以看一下Exception
的源代码。
public class Exception extends Throwable {
static final long serialVersionUID = -3387516993124229948L;
public Exception() {
super();
}
public Exception(String message) {
super(message);
}
public Exception(String message, Throwable cause) {
super(message, cause);
}
public Exception(Throwable cause) {
super(cause);
}
protected Exception(String message, Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
删掉一些注释就会妨碍吸纳,其实这个Exception
类什么都没有,都是针对不同参数的构造函数,但是构造函数其实都是直接调用的是Throwable
的构造函数,也没有做一些其他的事情。
那么既然是这样的话,那么是不是自定义的异常类,直接继承Throwable
和继承Exception
效果其实一样的呢?应该是的。
本来还想再看一下Throwable
的源代码的,的确也看了,但是看到一些native
的方法就不想贴出来了。
下面就是一个很经典的自定义的异常类。
public class MyException extends Exception {
public MyException() {
}
//这里可以不用显示地调用super(),因为函数里面没有其他东西
//如果有其他东西的话,那么还是需要使用super()进行显示调用的
public MyException(String msg) {
}
}
其实自定义的异常类,最重要的是异常的名字,通过自定义异常,然后抛出自定义的异常,可以清楚地通过异常的名字,看到具体是什么异常被抛出了,从而清楚地定位问题。
题外话
最近在进行Web开发的时候一直在想一个问题,比如有个查询数据库的操作,这个查询操作,可能会返回null
,也可能会返回n条纪录(如果为null的话,那么很有可能在外层引起空指针异常),那么如果返回null
的话,是在底层就将其使用异常机制抛出,强行告诉外层进行异常捕获,还是说什么都不做,在外层通过判断是否为null进行处理呢?