Java异常处理(详版)
java.lang.Throwable:是Java语言中所有错误或异常的超类
-
Exception:编译器异常,进行编译Java程序出现的问题
RuntimeException:运行期异常,Java程序运行过程中出现的问题
-
Error:错误
错误就相当于得了一个无法治愈的毛病,必须修改源代码,程序才能继续工作
throw关键字
作用
可以使用throw关键字在指定的方法中抛出指定的异常
使用格式
throw new xxxException(异常产生的原因)
注意
-
throw关键字必须写在方法内部
-
throw关键字后边new的对象必须是Exception或是Exception的子类
-
throw抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后边创建的是RuntineException或者是其子类,我们可以不处理,默认交给JVM处理(打印异常处理,中断程序)
throw关键字后边创建的是编译异常(写代码时报错),我们就必须处理这个异常,要么throws,要么try......catch
if(arr == null){ throw new NullPointerException("传递过来数组的值是null"); } if(index < 0 || index > arr.length-1){ throw new ArrayIndexOutOfBoundsException("传递的数组超出了数组的使用范围"); }
RuntimeException及其子类
NullPointerException
ArrayIndexOutOfBoundsException(extends IndexOutOfBoundsException)
IndexOutOfBoundsException
编译异常
FileNotFoundException
检查对象是否为空的方法
Objects中的静态方法
java.util.Objects
public static <T> T requireNonNull(T obj) :检查指定的对象引用不是 null
源码:
public static <T> T requireNonNull(T obj) { if(obj == null) throw new NullPointerException(); return obj; }
声明异常throws
异常处理的第一种方式,交给别人处理
作用
-
当方法内部抛出异常对象时,那么我们就必须处理这个异常对象
-
可以使用throws关键字处理异常处理对象,会把异常对象声明抛出给方法的调用者(自己不处理,给别人处理),最终交给JVM处理 → 中断处理
使用格式
在方法声明时使用
修饰符 返回值 方法名 (参数列表) throw AAAException, BBBException{
throw new AAAException("产生原因");
throw new BBBExcpetion("产生原因");
......
}
注意事项
-
throws关键字必须写在方法声明处
-
throws关键字后面声明的异常必须是Exception或者其子类
-
方法内部如果抛出了多个异常对象,那么throws后面必须也声明多个异常
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
-
调用了一个声明抛出异常的方法,我们就必须处理声明的异常
继续使用throws抛出异常,交给方法的调用者处理,最终交给JVM
try......catch
捕获异常try...catch
格式
try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,异常对象之后,怎么处理异常对象
}
......
catch(异常类名 变量名){
......
}
注意事项
-
try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常
-
如果try中产生了异常(在try语句块中产生该异常之后的语句不会再运行),那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码
如果try中没有产生异常,那么就不会执行catch中的语句,执行完毕try中的处理逻辑,继续执行try...catch之后的代码
finally代码块
无论是否出现异常都会执行
注意
-
finally不能单独使用,必须和try一起使用
-
finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要释放资源(e.g. IO)
-
如果finally有return语句,永远返回finally中的结果,应该避免这种情况的发生
public static void main(String[] args) { int e = test(); System.out.println(e); } public static int test() { int e = 10; try { return e; } catch (Exception e1) { // TODO: handle exception System.out.println("hhh"); } finally { return 100; } }
运行结果: 100
Throwable类中定义的三个异常处理的方法
String getMessage() 返回此可抛出的简短描述
String toString() 返回此throwable的详细消息字符串(重写Object的toString方法)
void printStackTrace() 将此throwable和其追溯打印到标准错误流
多个异常捕获处理
-
多个异常分别处理
try { int []arr = {1, 2, 3, 4, 5}; System.out.println(arr[5]); } catch (Exception e) { e.printStackTrace(); } try { List<Integer> list = java.util.List.of(1, 2, 3, 4, 5); System.out.println(list.get(5)); } catch (Exception e) { e.printStackTrace(); }
-
多个异常一次捕获,多次处理
try { int []arr = {1, 2, 3, 4, 5}; System.out.println(arr[5]); List<Integer> list = java.util.List.of(1, 2, 3, 4, 5); System.out.println(list.get(5)); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); }
注意:如果catch里面定义的异常变量有子父类关系,那么子类异常变量必须写在上面,否则会报错
-
多个异常一次捕获一次处理
try { int []arr = {1, 2, 3, 4, 5}; System.out.println(arr[5]); List<Integer> list = java.util.List.of(1, 2, 3, 4, 5); System.out.println(list.get(5)); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); }
子父类异常
-
如果父类抛出多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
-
父类方法没有抛出异常,子类重写父类方法时也不可抛出异常。此时子类产生该异常只能捕获处理,不能声明抛出
自定义异常
Java提供的异常类不够我们使用,需要自己定义一些异常类
格式
public class XXXException extends Exception | RuntimeException {
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
参考Exception类构造方法的源代码
public Exception() { super(); } /** * Constructs a new exception with the specified detail message. The * cause is not initialized, and may subsequently be initialized by * a call to {@link #initCause}. * * @param message the detail message. The detail message is saved for * later retrieval by the {@link #getMessage()} method. */ public Exception(String message) { super(message); } /** * Constructs a new exception with the specified detail message and * cause. <p>Note that the detail message associated with * {@code cause} is <i>not</i> automatically incorporated in * this exception's detail message. * * @param message the detail message (which is saved for later retrieval * by the {@link #getMessage()} method). * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A {@code null} value is * permitted, and indicates that the cause is nonexistent or * unknown.) * @since 1.4 */
注意
-
自定义异常类的名称一般都是以Exception结尾,说明该类是一个异常类
-
自定义异常类必须继承Exception或RuntimeException
继承Exception:那么自定义的异常类就是一个编译器异常,如果方法内部抛出了编译器异常,就必须处理这个异常,要么throws,要么try...catch
继承RuntimeException:那么自定义的异常类就是一个运行期异常,