异常处理(throw、throws、try-catch)
Java异常处理的五个关键字try、catch、finally、throw、throws
1.抛出异常throw
在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接收参数。那么,当调用方法使用接收到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。
在Java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?
1.创建一个异常对象,封装一些提示信息(信息可以自己编写)。
2.需要将这个异常对象告知给调用者:通过关键字throw就可以完成。throw异常对象。
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
使用格式:
throw new 异常类名(参数);
注意:
1.throw关键字必须写在方法的内部
2.throw关键字后边new的对象必须是Exception或者是Exception的子类对象
3.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象。
两种处理方式:
A.throw关键字后面创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
public static void main(String[] args) { int[] arr = {1,2,3}; int value = getElement(arr,3); System.out.println(value); } private static int getElement(int[] arr, int index) { /* 我们可以对传递的参数数组,进行合法性校验 如果数组arr的值是null 那么我们就抛出空指针异常,告知方法的调用者"传递的数组的值是null" */ if(arr == null){ // 空指针异常 // throw用在方法内,用来抛出一个异常对象 // 将这个异常对象传递到调用者处,并结束当前方法的执行。 // NullPointerException是运行期异常RuntimeException异常的子类 // 不用处理,默认交给JVM处理 throw new NullPointerException("传递的数组的值是null"); } /* 对传递过来的参数index进行合法性校验 如果index范围不在数组的索引范围内,就抛出"数组索引越界异常",告知方法的调用者 */ if(index < 0 || index > arr.length - 1){ // ArrayIndexOutOfBoundsException是运行期异常RuntimeException异常的子类 throw new ArrayIndexOutOfBoundsException("数组索引越界异常"); } int value = arr[index]; return value; }
运行截图:
代码规范:
必须对方法传过来的参数进行合法性校验,如果参数不合法,那么我们就必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题。
2.Objects非空判断
之前学过一个类Objects,由静态的实用方法组成,这些方法是null-save或null-torelent,那么在它的源码中,对对象为null的值进行了抛出异常操作。
public static <T> requireNonNull(T obj):查看指定引用对象不是null
public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
public static void method(Objects obj){ /*// 对传递过来的参数进行合法性判断,判断是否为null if (obj == null) { throw new NullPointerException("传递的参数为null");*/ // 第二种方法:调用Objects的方法 // Objects.requireNonNull(obj); Objects.requireNonNull(obj,"该参数传递的值是null"); }
B.throw关键字后面创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try...catch
3.声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲),那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。
声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2...{ }
注意:
1.throws关键字必须写在方法声明处
2.throws关键字后边声明的异常必须是Exception或者Exception的子类
3.方法内部如果抛出多个异常对象,那么throws后面必须也声明多个异常,如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可。
4.调用一个声明抛出异常的方法,就必须处理声明的异常,要么继续使用throws声明抛出交给方法的调用者,最终给JVM。要么try catch自己处理异常。
public static void main(String[] args) throws IOException { String fileName = "d:\\a.txt"; // 继续使用thrxows声明异常,抛给JVM readFile(fileName); } /* 定义一个方法,对传递的文件路径进行合法性判断 如果路径不是"c:\\a.txt",那么我们就抛出文件找不到异常对象,告知方法的调用者 */ public static void readFile(String fileName) throws IOException { // 加上throww声明异常 // 返回给主方法 if(!fileName.equals("c:\\\\a.txt")){ // 路径异常 // 报错,编译异常 throw new FileNotFoundException("传递的文件路径不是c:\\\\a.txt"); } /* 如果传递的路径,不是.txt结尾 那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对 */ // if(!fileName.split(".")[1].equals("txt") ){ if(!fileName.endsWith(".txt")){ // 报错,编译异常,需要声明 throw new IOException("文件的后缀名不对"); } System.out.println("路径没问题,读取文件"); }
4.捕获异常try...catch
如果异常出现的话,会立刻终止程序,所以我们得处理异常:
1.该方法不处理,而是声明抛出,由该方法得调用者来处理(throws)
2.在方法种使用try-catch的语句块来处理异常
try-catch的方法就是捕获异常
捕获异常:Java种对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。
捕获异常语法如下:
try{ 编写可能会出现异常的代码 }catch(异常类型 e){ 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 }
注意:
1.try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
2.如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕后catch中的处理逻辑,继续执行try...catch之后的代码。
如果try中没有产生异常,那么就不会执行catch中的异常处理逻辑,执行完毕后catch中的处理逻辑,继续执行try...catch之后的代码。
public static void main(String[] args) { try{ readFile("d:\\a.tt"); }catch(IOException e){ // try中抛出什么异常对象,catch就定义什么异常变量, // 用来接收这个异常对象 System.out.println(e); } // try catch执行后,继续执行后续代码 System.out.println("后续代码"); } public static void readFile(String fileName) throws IOException { // 加上throws声明异常 /* 如果传递的路径,不是.txt结尾 那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对 */ if(!fileName.endsWith(".txt")){ // 报错,编译异常,需要声明 throw new IOException("文件的后缀名不对"); } System.out.println("路径没问题,读取文件"); }
运行截图: