异常处理try_catch和throws
throw关键字
package 异常学习;
/*
* java.lang.Throwable:类是java语言中所有错误或异常的超类
* Excepttion:编译期异常,进行编译Java程序错误
* RuntimeException:运行期异常,java程序在运行过程中出现的异常
* Error:错误
* 错误必须通过修改源代码,程序才能继续执行
*
* 异常产生过程解析(分析异常怎么产生的们如何处理异常)
* 方法将异常抛给main方法,main方法将异常抛给JVM
*
* 异常的处理:
* 1.抛出异常throw关键字,可以在指定的方法中抛出指定的异常
* 使用格式:
* throw new ***Exception("异常产生的原因");
* 注意事项:
* 1.throw关键字必须写在方法的内部
* 2.throw关键字后边new对象必须是Exception或者是Exception的子类对象
* 3.throw关键字抛出指定的异常对象。我们就必须处理这个异常对象
* throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常,中断程序)
* throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try...catch...
*
* */
public class Demo01Exception {
public static void main(String[] args) {
//创建数组 并赋值
int[] arr = {1, 2, 3, 4};
// int[] arr = null;
int e = getElements(arr, 6);//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
// System.out.println(e);
}
/*
* 创建一个方法,获取数组指定索引的元素
* 以后工作中,我们首先对方法传递过来的参数进行合法性校验,
* 如果参数不合法,纳闷我们就必须使用抛出异常的方式 告知方法的调用者,传递的参数有问题
* 注意:
* 异常.NullPointerException: 传递的数组值是空是一个运行期异常,我们不用处理,默认交给JVM处理
* */
public static int getElements(int[] arr,int index) {
/*
* 我们对传递过来的参数进行合法性校验
* 如果数组arr的值是null,那么我们就抛出空指针异常,告知调用者传递的数组值是空
* */
if (arr == null) {
throw new NullPointerException("传递的数组值是空");
}
/*
* 我们可以对传递过来的index进行合法性校验,如果index不在数组索引范围内
* 就抛出数组索引越界异常
* */
if (index < 0 || index > arr.length - 1) {
throw new ArrayIndexOutOfBoundsException("数组的索引越界了");
}
int ele = arr[index];
return ele;
}
}
########################运行结果#################
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 数组的索引越界了
at 异常学习.Demo01Exception.getElements(Demo01Exception.java:55)
at 异常学习.Demo01Exception.main(Demo01Exception.java:29)
Objects非空判断
package 异常学习;
import java.util.Objects;
/*
* Objects类中的静态方法:
* public static <T> T requireNonNull(T obj) :查看指定引用对象不是null
* 源码:
* public static <T> T requireNonNull(T obj) {
* if (obj == null)
* throw new NullPointerException();
* return obj;
* }
*
* */
public class Demo02Objects {
public static void main(String[] args) {
method(null);
}
//创建一个方法
public static void method(Object obj) {
// //对传递的参数进行合法性判断,判断是否为空
// if (obj == null) {
// throw new NullPointerException("传递的对象值是空");
// }
//等价于直接调用Objects的非空判断
// Objects.requireNonNull(obj);
Objects.requireNonNull(obj, "传递的对象值是空");
}
}
#####################运行结果#############
Exception in thread "main" java.lang.NullPointerException: 传递的对象值是空
at java.base/java.util.Objects.requireNonNull(Objects.java:233)
at 异常学习.Demo02Objects.method(Demo02Objects.java:29)
at 异常学习.Demo02Objects.main(Demo02Objects.java:18)
第一种方式:throws处理异常
package 异常学习;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* throws关键字:异常处理的第一种方式,交给别人处理
* 作用:
* 当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象
* 可以使用throws关键字处理异常对象,会把异常对象声明抛给调用者使用(自己不处理,交给别人处理),最终交给JVM处理,中断处理
* 使用格式:
* 修饰符 返回值类型 方法名(参数列表) throws AAAAException,BBBBException...{
* throw new AAAAException("产生的原因"));
* throw new BBBBException("产生的原因"));
* ....
* }
* 注意:
* 1.throws关键字必须写在方法声明处
* 2.throws关键字后边声明的异常必须是Exception或者是Exception的子类
* 3.方法内部如果抛出了多个异常,那么throws关键字后边也必须声明多个异常
* 如果抛出的异常 有子父类关系,那么直接声明父类异常即可
* 4.调用了一个声明抛出异常的方法,我们就必须处理声明的异常
* 要么继续使用throws抛出异常,要么try...catch
* */
public class Demo03Throws {
public static void main(String[] args) throws IOException { //调用readFile方法时,也需要继续抛出异常 ,FileNotFoundException是IOException的子类,直接声明父类异常就可以
readFile("c:\\a.txt");
}
//定义一个方法,对传播的文件路径进行合法性判断
//注意:FileNotFoundException是编译异常,必须处理这个异常
//可以使用throws继续声明抛出这个异常对象,让方法调用者处理
public static void readFile(String filename) throws IOException {
if (!filename.equals("c:\\b.txt")) {
throw new FileNotFoundException("传递的路径不是c:\\a.txt");
}
/*
* 如果传递的路径不是.txt结尾
* 抛出后缀名不对的异常
* */
if (!filename.endsWith(".txt")) {
throw new IOException("文件名后缀不对");
}
System.out.println("路径没有问题,读取文件");
}
}
################运行结果#####################
Exception in thread "main" java.io.FileNotFoundException: 传递的路径不是c:\a.txt
at 异常学习.Demo03Throws.readFile(Demo03Throws.java:36)
at 异常学习.Demo03Throws.main(Demo03Throws.java:27)
第二种方式:try_catch 处理异常
Throwable类中3个异常处理的方式
package 异常学习;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 异常处理的第二种方式:(自己处理)
* 格式:
* try{
* 可能产生异常的代码
* }catch(定义一个异常的变量,用来接收try抛出的异常对象){
* 异常的处理逻辑,一般在工作中,会把异常信息记录到一个日志中
* }
* ....
* catch(异常类型 变量名){
* }
*
* 注意:
* 1.try中可能出现多个异常对象,那么就可以使用多个catch来处理这些异常
* 2.如果try产生异常。那么就执行catch中的异常处理逻辑,执行完毕catch中的逻辑,继续执行try...catch之后的代码
* 如果try没有产生异常,就不会处理catch中的处理逻辑,直接执行try...catch之后的代码
*
* */
public class Demo04TryCatch {
public static void main(String[] args) {
try {
readFile("d:\\a.tx");
System.out.println("这里需要使用finally代码块,才能够在有异常的时候读到");
} catch (IOException e) { //try抛出什么异常对象,catch就定义什么异常对象,用来接收这个异常对象
// System.out.println("catch--传递的文件地址后缀不对");
/*
* Throwable类中定义了3个异常处理的方法:
* String getMessage() 返回此 throwable 的简短描述
* String toString() 返回此 throwable 的详细描述
* void printStackTrace() 将此 throwable 及其追踪输出至标准错误流
* */
// System.out.println(e.getMessage());
/*运行结果:文件名后缀不对
* */
// System.out.println(e.toString());
/*运行结果:java.io.IOException: 文件名后缀不对
* */
e.printStackTrace();
/*运行结果:java.io.IOException: 文件名后缀不对
* at 异常学习.Demo04TryCatch.readFile(Demo04TryCatch.java:58)
* at 异常学习.Demo04TryCatch.main(Demo04TryCatch.java:27)
* */
}
System.out.println("后续代码");
}
public static void readFile(String filename) throws IOException {
/*
* 如果传递的路径不是.txt结尾
* 抛出后缀名不对的异常
* */
if (!filename.endsWith(".txt")) {
throw new IOException("文件名后缀不对");
}
System.out.println("路径没有问题,读取文件");
}
}
##########################运行结果################
java.io.IOException: 文件名后缀不对
at 异常学习.Demo04TryCatch.readFile(Demo04TryCatch.java:63)
at 异常学习.Demo04TryCatch.main(Demo04TryCatch.java:27)
后续代码
finally代码块
package 异常学习;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* finally:有一些特定的代码无论异常是否发生,都需要执行。
* 另外,因为异常会引发程序跳转,导致有些语句执行不到。
* 而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
* 如果finally有return语句,永远返回finally中的结果,应该避免该情况.
*
* 格式:
* try{
* 可能产生异常的代码
* }catch(定义一个异常的变量,用来接收try抛出的异常对象){
* 异常的处理逻辑,一般在工作中,会把异常信息记录到一个日志中
* }
* ....
* catch(异常类型 变量名){
* }finally{
* 无论是否出现异常都会执行
* }
*
* 注意:
* 1.finally不饿能单独使用,必须和try一起使用
* 2.finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)
*
* */
public class Demo05finally {
public static void main(String[] args) {
try {
readFile("d:\\a.tx");
} catch (IOException e) {
e.printStackTrace();
}finally {
//无论是否出现异常都会执行
System.out.println("资源释放");
}
}
public static void readFile(String filename) throws IOException {
/*
* 如果传递的路径不是.txt结尾
* 抛出后缀名不对的异常
* */
if (!filename.endsWith(".txt")) {
throw new IOException("文件名后缀不对");
}
System.out.println("路径没有问题,读取文件");
}
}
#####################运行结果################
java.io.IOException: 文件名后缀不对
at 异常学习.Demo05finally.readFile(Demo05finally.java:51)
at 异常学习.Demo05finally.main(Demo05finally.java:33)
资源释放
多异常处理
package 异常学习;
import java.util.List;
/*
* 多个异常使用捕获又该如何处理呢?
* 1. 多个异常分别处理。
* 2. 多个异常一次捕获,多次处理。
* 3. 多个异常一次捕获一次处理。
*
* 此外:父类是什么异常,子类就是什么异常
* */
public class Demon06多异常处理 {
public static void main(String[] args) {
//1. 多个异常分别处理。
/*try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException a) {
a.printStackTrace();
}
try {
List<Integer> list = List.of(1, 2, 3);
System.out.println(list.get(3));
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
System.out.println("后续代码");
*/
//2.多个异常一次捕获,多次处理。
/*try {
int[] arr = {1, 2, 3};
System.out.println(arr[4]);
List<Integer> list = List.of(1, 2, 3);
System.out.println(list.get(6));
} catch (ArrayIndexOutOfBoundsException a) {
a.printStackTrace();
} catch (IndexOutOfBoundsException e) { //catch中定义的异常对象,如果有子父类关系,那么子类的异常变量必须写在上面,否则就会报错
e.printStackTrace();
}
*/
//3. 多个异常一次捕获一次处理。
try {
int[] arr = {1, 2, 3};
List<Integer> list = List.of(1, 2, 3);
System.out.println(list.get(6));
System.out.println(arr[4]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#################运行结果###############
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 3
at java.base/java.util.ImmutableCollections$ListN.get(ImmutableCollections.java:547)
at 异常学习.Demon06多异常处理.main(Demon06多异常处理.java:51)
自定义异常
package 异常学习;
/*
* 自定义异常类:
* 格式:
* public class XXXException extends Exception | RunTimeException{
* 添加一个空参数的构造方法;
* 添加一个带异常信息的构造方法;
* }
* 注意:
* 1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
* 2.必须继承Exception(编译异常,必须处理,要么throws要么try..catch) | RunTimeException(运行异常)(无需处理,交给JVM处理)
* */
public class Demo07自定义异常 extends Exception {
public Demo07自定义异常() {
super();
}
/*
* 添加一个带异常信息的构造方法
* 查看源码都会发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
* */
public Demo07自定义异常(String message) {
super(message);
}
}