目录
②通过try...catch处理(好处是出现异常之后后续代码继续执行)
格式如下(try和finally只能是一个,catch可以是多个):
一、异常概述
1、简介
异常指的是在程序执行过程中,出现的非正常情况,最终导致jvm非正常停止;
(异常并不是指语法错误,语法错误,编译不通过,不会产生字节码文件,就不会运行;)
2、异常体系
异常类Throwable有两个子类:Error(不能处理的错误)和Exception(可处理的异常),我们平常所说的异常指的是Exception;
Exception:编译(写代码)期异常(可处理的异常);
RuntimeException:运行期异常(可处理的异常);
3、编译期异常的2种处理方式
①上抛给虚拟机处理(缺点是虚拟机拿到异常后悔终止程序)
public class MyException {
//将异常上抛给虚拟机处理,出现异常虚拟机悔停止程序运行
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("1999-09-09");
}
}
②通过try...catch处理(好处是出现异常之后后续代码继续执行)
public class MyException {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse("1999-0909");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("后续代码继续执行");
}
}
异常:
java.text.ParseException: Unparseable date: "1999-0909"
at java.base/java.text.DateFormat.parse(DateFormat.java:395)
at study.exception.MyException.main(MyException.java:11)
后续代码继续执行
4、运行期异常
public class MyException {
public static void main(String[] args) {
//下面演示运行期异常
int[] arr = {1,2,3};
try {
System.out.println(arr[3]);
}catch (Exception e){
System.out.println(e);//打印这个异常
//java.lang.ArrayIndexOutOfBoundsException: 3
}
System.out.println("后续代码继续执行");
}
}
5、Error错误
public class MyException {
public static void main(String[] args) {
//Error错误
int[] arr = new int[1024*1024*1024];
//java.lang.OutOfMemoryError: Java heap space
}
}
二、分析异常产生的过程
三、异常的处理
throw关键字
作用:
可以使用throw关键字在指定的方法中抛出指定的异常;
使用格式:
throw new XXXException("异常产生的原因");
注意:
①throw关键字必须写在方法的内部;
②throw关键字关键字后面new的对象必须是Exception对象或Exception子类的对象;
③throw关键字抛出指定的异常对象,我们必须处理:
- throw关键字后面创建的是RuntimeExpection或者是RuntimeException的子类,默认不处理,交给Jvm处理;
- throw关键字后面是编译(写代码)异常,我们必须处理,要么上抛处理,要么try...catch;
以后工作中:
我们必须对方法接收的参数进行合法性校验,若参数不合法则通过抛出异常的方式告诉调用者;
例如(备注:这里作为演示,其实这两个异常都是运行期异常,JVM会自动处理):
public class MyException {
public static void main(String[] args) {
int[] a = {};
System.out.println(getElement(a,0));
}
private static int getElement(int[] arr,int index){
if(arr == null){
throw new NullPointerException("传入的数组为空");
}else if(index > arr.length-1){
throw new ArrayIndexOutOfBoundsException("传递的索引值超出了数组的长度");
}
return arr[index];
}
}
所抛出的异常:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的索引值超出了数组的长度
at study.exception.MyException.getElement(MyException.java:13)
at study.exception.MyException.main(MyException.java:7)
四、Objects非空判断
public class MyObjects_NonNull {
public static void main(String[] args) {
//判断一个对象是否为空
System.out.println(Objects.nonNull(null));//false
//跟想象中不太一样,用的时候要再深入研究
System.out.println(Objects.nonNull(""));//true
int[] a = {};
//跟想象中不太一样,用的时候要再深入研究
System.out.println(Objects.nonNull(a));//true
}
}
五、异常处理的第一种方式(上抛异常)
throws关键字:
异常处理的第一种方式:交给别人处理;
作用:
当方法内部抛出异常对象的时候,就必须对这个异常对象进行处理;
可以使用throws关键字将异常抛给调用者处理——最终抛给JVM处理(JVM终端程序的执行);
使用格式(在方法声明时使用):
修饰符 返回值类型 方法名(参数列表) throws AAAException,BBBException...{
throw new AAAException("产生原因");
throw new BBBException("产生原因");
……
}
注意:
①throws关键字必须写在方法声明处;
②throws关键字后面声明的异常必须是Exception或者是Exception的子类;
③方法内部如果抛出了多个异常,那么throws后面也必须声明多个异常(若有子父类关系,那么直接声明父类即可);
④调用了一个方法抛出的异常,我们就必须处理声明的异常:
- 要么交给方法调用者处理,最终交给JVM;
- 要么交给try...catch自己处理;
package study.exception;
import java.io.FileNotFoundException;
public class MyObjects_NonNull {
//上抛给调用者处理-JVM虚拟机
public static void main(String[] args) throws FileNotFoundException {
getFile("D://a.txt");
}
//上抛给调用者处理-main方法
private static void getFile(String path) throws FileNotFoundException {
if(!path.equals("C://a.txt")){
throw new FileNotFoundException("未传入指定文件路径");
}
}
}
异常:
Exception in thread "main" java.io.FileNotFoundException: 未传入指定文件路径
at study.exception.MyObjects_NonNull.getFile(MyObjects_NonNull.java:13)
at study.exception.MyObjects_NonNull.main(MyObjects_NonNull.java:8)
六、异常处理的第二种方式(捕获异常)
try...catch法
格式:
try{
//可能产生异常的代码
}catch(异常1){
//出现异常1之后的处理逻辑
}catch(异常2){
//出现异常2之后的处理逻辑
}
//catch可以有多个,try只能有一个
注意:
①try若可能抛出多个异常,可以用多个catch,但只能有一个try;
②如果try中产生了异常,就会执行相应的catch里面的异常处理逻辑,执行完catch之后还会继续执行try...catch之后的代码;
反之,如果try中没有产生异常,就不会执行catch里面的异常处理逻辑,try里面的代码执行完毕之后执行try...catch之后的代码;
代码演示:
package study.exception;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MyObjects_NonNull {
public static void main(String[] args) {
//可能产生的异常不再上抛,直接处理
try {
//可能产生异常的代码
getFile("C://a.tx");
} catch (IOException e) {
//出现异常之后的处理逻辑
e.printStackTrace();//输出异常
}
System.out.println("后续代码继续执行");
}
//上抛给调用者处理-main方法
private static void getFile(String path) throws IOException {
if(!path.equals("C://a.txt")){
throw new FileNotFoundException("未传入指定文件路径");
}
}
}
七、Throwable中3个处理异常的方法
1、String getMessage():
返回此throwable的简短描述
2、String toString():
返回throwable详细消息字符串
3、void printStackTrace():
JVM打印异常对象,默认调用此方法(异常信息最全面)
4、代码示例
package study.exception;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MyObjects_NonNull {
public static void main(String[] args) {
//可能产生的异常不再上抛,直接处理
try {
//可能产生异常的代码
getFile("C://a.tx");
} catch (IOException e) {
//出现异常之后的处理逻辑
e.printStackTrace();//输出异常
System.out.println(e.toString());
System.out.println(e.getMessage());
}
System.out.println("后续代码继续执行");
}
//上抛给调用者处理-main方法
private static void getFile(String path) throws IOException {
if(!path.equals("C://a.txt")){
throw new FileNotFoundException("未传入指定文件路径");
}
}
}
异常信息:
(最全面的异常e.printStackTrace();)
java.io.FileNotFoundException: 未传入指定文件路径
at study.exception.MyObjects_NonNull.getFile(MyObjects_NonNull.java:23)
at study.exception.MyObjects_NonNull.main(MyObjects_NonNull.java:11)
(返回throwable详细消息字符串System.out.println(e.toString());)
java.io.FileNotFoundException: 未传入指定文件路径
(返回此throwable的简短描述System.out.println(e.getMessage());)
未传入指定文件路径
后续代码继续执行
八、finally代码块
finally代码块:
有一些代码是否出现异常都要执行,就可以写在finally代码块中;
格式如下(try和finally只能是一个,catch可以是多个):
try {
//可能产生异常的代码
}catch (/*异常种类*/){
//出现异常之后的处理逻辑
}catch (/*异常种类*/){
//出现异常之后的处理逻辑
}finally {
//是否产生异常都会执行的代码
}
注意:
①若try中有多行代码,那么前面的代码出现异常的时候后面的代码就不能执行了,所以可以放在finally中执行;
②finally不能单独使用;
③finally代码块一般用于资源释放,无论是否出现异常都会执行;
九、多个异常的捕获
1、三种处理方式:
①分别捕获和处理;
②多个异常,一次捕获,多次处理;
③多个异常,一次捕获,一次处理;
2、注意
①一个try多个catch,如果异常有子父类关系,子类必须写在父类上面,否则会报错;
②如果try中存在两个可能存在的异常,当第一个出现异常,try中的后续代码也是不能执行的;
3、代码示例
package study.exception;
import java.util.List;
public class ManyException {
public static void main(String[] args) {
//1、分别捕获和处理
try {
int[] x = {1,2,3};
System.out.println(x[3]);//ArrayIndexOutOfBoundsException: 3
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e.toString());
}
try {
List<Integer> list = List.of(1,2,3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (IndexOutOfBoundsException e){
System.out.println(e.toString());
}
//2、一次捕获,多次处理
try {
int[] x = {1,2,3};
System.out.println(x[3]);//ArrayIndexOutOfBoundsException: 3
System.out.println("try中后续代码");
List<Integer> list = List.of(1,2,3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e.toString());
}catch (IndexOutOfBoundsException e){
System.out.println(e.toString());
}
//3、一次捕获,一次处理
try {
int[] x = {1,2,3};
System.out.println(x[3]);//ArrayIndexOutOfBoundsException: 3
System.out.println("try中后续代码");
List<Integer> list = List.of(1,2,3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (IndexOutOfBoundsException e){
//IndexOutOfBoundsException一个异常可以收多种错误(父类)
System.out.println(e.toString());
}
}
}
十、finally代码块种有return语句的情况
如果finally代码块种有return语句的情况,永远返回finally中的结果,应该避免该情况;
其实不太懂具体啥意思,以后使用到要细细研究!
十一、子父类异常
概述:
①如果父类抛出了多个异常,子类重写父类方法时,要抛出和父类相同的异常或者父类的子类的异常或者不抛出异常;
②如果父类没有抛出异常,子类重写父类的方法也不可能抛出异常,此时子类产生异常,只能捕获处理,不能声明抛出;
十二、自定义异常类
1、概述
定义一个异常类跟写一个普通类相似,但要继承Exception或者RuntimeExpection
2、格式
public class XXXException extends Exception | RuntimeException{
//添加一个无参构造方法
//添加一个带异常信息的构造方法
}
3、注意
①自定义异常类一般都以Exception结尾,说明该类是一个异常类;
②自定义异常类必须要继承Exception或者RuntimeExpection;
- 继承Exception:是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理此异常(要么throws要么try...catch);
- 继承RuntimeExpection:无需处理,交给虚拟机处理即可——中断程序;
4、代码示例
public class MyDiyException extends Exception {
//无参构造
public MyDiyException() {
super();
}
//带异常信息的构造
public MyDiyException(String e){
//父类有带异常信息的构造,直接交给父类处理
super(e);
}
}