java异常处理-1
https://developer.aliyun.com/article/1515774
三、常见异常
java内部提供了一些异常,用来描述经常发生的错误,其中,有的需要程序员极性捕捉处理或声明抛出。有的是由java虚拟机自动进行捕捉
java常见的异常类如表:
java常见的异常类
异常类 | 说明 |
ClassCastException | 类型转换异常 |
ClassNotFoundException | 未找到相应的类异常 |
ArithmeticException | 算术异常 |
ArrayIndexOutOfBoundsException | 数组下标越界异常 |
ArrayStoreException | 数组中包含不兼容的值抛出的异常 |
SQLException | 操作数据库异常类 |
NullPointerException | 空指针异常 |
NoSuchFieldException | 未找到字段异常 |
NoSuchMethodException | 方法未找到抛出的异常 |
NumberFormatException | 字符串转化为数字抛出的类异常 |
NegativeArraySizeException | 数组元素个数为负数抛出的异常 |
StringIndexOutOfBoundsException | 字符串索引超出范围抛出的异常 |
IOException | 输入输出异常 |
IllegalAccessException | 不允许访问某类异常 |
InstantiationException | 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常 |
EOFException | 文件已结束异常 |
FileNotFoundException | 文件未找到异常 |
以上异常的出现场景希望读者可以自行研究。
四、自定义异常
使用java内置的异常类可以处理在编程期间出现的大多数异常情况,但是仍有部分比较有特性的异常是java内置异常没有覆盖到的。例如:对于需要传入整数的一个方法,你可能会觉得,传入 一个负数是不符合你的期望,认为负数作为这个方法的参数为一个错误的值,但是对于java来说,它不会将其视为一个错误或者异常。
所以为了能个性化地去解决这些在特殊情况才能出现的异常,java引入了自定义异常类,用户只需要继承Exception类即可以自定义异常类。
那么具体如何自定义异常类呢?
① 首先,在java中异常都是作为类的实例的形式出现的,所以我们应该先定义自定义的类,类名设为MyException(自定义类名视使用场景况而定),然后由该类继承Exception类:
代码案例:
public class MyException extends Exception{ // 声明这个MyException类并让其继承Exception类 public MyException (String ErrorMessage){ // 调用构造方法 super(ErrorMessage); // 给父类Exception传参 } }
字符串ErrorMessage是要输出的错误信息。
② 使用throw关键字,在需要的时候抛出异常,就比如我们经常使用ArrayList表里面的set方法:
里面就是使用了rangeCheck()方法来检查index是否越界,点击查看rangeCheck方法可以看到如下:
在这里通过使用throw 关键字抛出对应的异常信息,里面的outOfBoundMsg(index)返回一个错误 的异常信息的字符串,对应我们自定义异常的 ErrorMessage :
然后使用构造方法构造new 出一个IndexOutOfBoundsException 的实例并抛出异常。
我们使用自定义异常配合try- catch语句来模拟这个过程:
public class Main { private static void checkMySet(int pos,int len) throws MyException{ if(pos >= len){ throw new MyException("指定的下标超过已有的最大下标位置"); } else if (pos < 0 ) { throw new MyException("指定下标小于0!"); }else { System.out.println("下标数值正确!"); } } public static void set(int[] arr,int pos,int element) throws MyException { checkMySet(pos,arr.length); arr[pos] = element; } public static void main(String[] args) { int[] arr = new int[10]; try { set(arr,-4,10); // 可能抛出异常 } catch (MyException e) { System.out.println(e); // 进行捕捉 } } }
结果为:
程序正常退出。
throw关键字
throw关键字通常用于方法体重,并且抛出一个异常的实例化对象,对象被抛出后程序终止:
可以看到,如果在方法体内抛出对象的语句后面加上语句,那么后面的语句将永远不会执行到
代码案例如下:
public class Main { private static void Test(int pos) throws MyException{ if(pos >= 0){ throw new MyException("pos >= 0"); } System.out.println("checkEnded"); } public static void main(String[] args) { int[] arr = new int[10]; try { System.out.println("TestStart"); Test(0); System.out.println("TestEnd"); } catch (MyException e) { System.out.println(e); // 进行捕捉 } } }
执行结果:
可以看出来,在方法抛出异常后,该方法后面的语句也不会执行
如果要捕捉异常,就必须使用try - catch语句
此外,throw必须写在方法体内部 ,抛出的对象必须是Exception 或者 Exception 的子类对象。如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理 如果抛出的是编译时异常,用户必须处理,否则无法通过编译 。异常一旦抛出,其后的代码就不会执行
throws关键字
throws关键字通常被用来在声明方法的时候,指定其方法可能抛出的异常,多个异常可以用“,”逗号分割:
public static void Test () throws Exception1 , Exception2 , Exception3 {
//可能会抛出Exception1 , Exception2 , Exception3异常的方法体
}
从上面的代码案例中我们可以看到:checkMySet()方法中加入了if 语句来来判断是否抛出异常,有可能会抛出,也可能不会抛出,只要有抛出的可能,就需要在其方法后用throws关键字声明可能会抛出的异常类。
处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws 将异常抛 给方法的调用者来处理。
异常被throws 不断向上抛出,最终被catch 捕获并处理。
需要注意的是:
① throws必须跟在方法的参数列表之后
② 声明的异常必须是 Exception 或者 Exception 的子类
五、运行时异常
RuntimeException 异常是程序运行过程中产生的异常。它是Exception类的子类之一。
java类库的每个包中都定义了异常类,所有的类都是Throwable的子类,Throwable派生出两个子类,分别是Exception 和 Error 类。 Error 类及其子类用来描述java运行系统中的内部错误以及资源消耗的错误。
Exception类异常通过捕捉后程序可以继续正常执行。
其中RuntimeException的异常种类
从图中可以看出来,Throwable 是异常处理体系的顶层类,派生除了Error 和 Exception 两个重要的子类。Error 指的是java虚拟机无法解决的严重问题,例如jvm内部错误,资源耗尽等等,其代表为: StackOverflowError 和 OutOfMemoryError。
Exception 异常类为程序员可以正常捕捉并处理的异常。
RuntimeException异常
NullPointerException | 空指针异常 |
ArrayIndeOutOfBoundsException | 数组下标越界异常 |
ArithmeticException | 算术异常 |
SecurityException | 安全性异常 |
NegativeArrayException | 数组长度为负异常 |
IllegalArgumentException | 非法参数异常 |
ArrayStoreException | 数组中包含不兼容参数异常 |
六、异常处理流程
程序先执行 try 中的代码 如果 try 中的代码出现异常 , 就会结束 try 中的代码 , 看和 catch 中的异常类型是否匹配 . 如果找到匹配的异常类型, 就会执行 catch 中的代码 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者 . 无论是否找到匹配的异常类型, fifinally 中的代码都会被执行到 ( 在该方法结束之前执行 ). 如果上层调用者也没有处理的了异常, 就继续向上传递 . 一直到 main 方法也没有合适的代码处理异常 , 就会交给 JVM 来进行处理 , 此时程序就会异常终止。
java异常强制用户去考虑程序的强健性和安全性。当程序运行到某个方法可能会出现异常时,可以在当前方法中使用try - catch 语句捕获异常。
如果一个方法被覆盖的时候,则需要在他的上级方法中声明抛出相同异常或异常的子类。如果父类中抛出多个异常,则覆盖方法必须抛出那些异常的的一个子集,不能抛出新的异常。