一、异常分类
都是Throwable的子类:
- Exception(异常):程序本身可以处理的异常
- Error(错误):程序无法处理的错误,一般都是发生在虚拟机自身或者执行应用时。
- Checked(编译器要求必须检查的异常):Java编译会去检查它,要么使用try-catch语句捕获它,要么使用throws子句声明抛出它,不处理无法通过编译。
- Unchecked(编译器不要求处置的异常):包括运行时异常和错误
二、异常的处理
1. try-catch-finally
将可能引发异常的代码块放在try中,在catch语句中依次对抛出的异常进行捕获,但是一定要注意捕获的顺序,一定是先捕获子类异常,再捕获父类异常。捕获多种异常的时候可以使用catch(NulPointerException | IOException ex)进行捕获,注意各个异常之间用“ | ”隔开,并且这时异常变量使用隐式final修饰,无法再修改,单一异常捕获可以修改捕获到的异常。
finally可以做资源关闭等工作,因为除了在try或catch中调用了退出虚拟机的方法,否则finally块都会执行,并且finally会总是在return之前执行。因此不要在finally中使用return和throw,否则try和catch中的return和throw都会失效。因为当系统遇到return和throw时会首先去找finally块,执行finally中的内容,如果finally使用了则会直接结束该方法。
Java7加强之后的try可以自动实现资源的关闭,只要在try()中打开需要在程序结束时手动关闭的资源,这些资源都会在程序结束时自动关闭。因为JAVA7对几乎所有资源类都进行了重写,这些资源类都实现了AutoCloseable或Closeable接口,也就是实现close()方法。Closeable是AutoCloseable的子接口,前者的close()方法抛出IOException,后者抛出Exception异常,所以实现类在使用close()时可以抛出任何异常。 并且这时的try语句可以没有catch和finally!
2. throws
throws作为方法异常抛出的声明,在使用throws声明抛出异常时,异常会逐层上递,最终交给JVM,如果JVM也无法处理就会种植程序运行,打印异常的跟踪栈信息。子类抛出的异常不允许比父类多,子类方法声明的异常类型应该是父类方法声明的异常类型的子类或相同。
3. try-catch捕获的异常无须其调用者再次捕获,如果调用者也想要捕获该异常,则应该使用catch-throw,即在catch中throw该异常,这样调用者也可以捕获该异常,适合需要将异常信息(转译之后的信息)反馈给用户的时候使用。
public void fun1() throws Exception{ //Java7以前的方式
try {
System.out.println(5/0);
}
catch(Exception e) {
throw e ;
}
}
public void fun2() throws ArithmeticException {//Java7开始的方式
try {
System.out.println(5/0);
}
catch(Exception e) {
throw e;
}
}
//调用者
public static void main(String[] args) {
ExceptionTest exp = new ExceptionTest() ;
try {
exp.fun1() ;
}
catch(ArithmeticException e) {
System.err.println(e.getMessage());
}
}
三、自定义异常类
自定义Checked异常类需要继承Exception基类,而Runtime异常类则需要继承RuntimeException基类。然后需要为自定义的异常类定义两个构造器,一个无参构造器,以及一个参数为字符串的构造器。
public class SaleException extends Exception{
//无参构造器
public SaleException() {}
//带一个字符串参数的构造器
public SaleException(String str) {
super(str) ;
}
}