异常
异常概述:程序中出现了不正常得情况。程序在执行过程中,出现了非正常的情况,最终会导致JVM的非正常停止
注意:语法错误不算在异常体系中
异常体系:Throwable =》Error(严重问题,通过代码无法处理,比如内存溢出),Exception(称为异常类,他表示程序本身可以处理的问题)
Exception=》 RuntimeException及其子类(运行时异常,比如空指针异常,数组索引越界),除RuntimeException之外所有的异常(编译器必须处理的,否则程序不能通过编译,比如日期格式化)
Java文件====>(Java.exe 编译异常,是在编译成class文件时必须要处理的异常,也称之为受检异常)字节码文件====> (Java.exe 运行时异常,在编译成class文件按不需要处理,在运行字节码文件时可能出现的异常。也称之为非受检异常)运行结果
简单来说:
编译时异常就是在编译的时候出现的异常
运行时异常就是在运行时出现的异常。
JVM的默认处理方案
如果程序出现了问题,我们没有做任何处理,最终JVM会做默认的处理
1.把异常的名称,异常原因及异常出现的信息的位置等信息输出在了控制台
2.程序停止执行
异常处理方式-----throws
格式:
throws 异常类名;
注意:这个格式是写在方法的定义处,表示声明一个异常
public class test1 {
public static void main(String[] args) throws ParseException {
method1();//ParseException 解析异常 继续交给调用者处理 还是会交给虚拟机处理
//method2();//NullPointerException 空指针异常 此时调用者没有处理 还是会交给虚拟机处理
}
//告诉方法调用者,你调用我,有可能会出现这样的异常
//如果没有出现异常,正常执行
//出现异常,也是将异常交给调用者处理
//如果声明的异常是一个运行时异常,那么代码可以省略
private static void method2()throws NullPointerException {//throws NullPointerException 可以省略
int[] arr=null;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
//告诉方法调用者,你调用我,有可能会出现这样的异常
//如果没有出现异常,正常执行
//出现异常,也是将异常交给调用者处理
//如果声明的异常是一个编译时异常,那么代码必须先声明
private static void method1() throws ParseException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日");
sdf.parse("2022年10月10日");
}
}
throws声明异常
编译时异常因为在编译时就会检查,所以必须要写在方法后面进行显示声明
运行时异常因为在运行时才会发生,所以在方法后边可以不写
抛出异常对象-----throw
格式:
throw new 异常();
注意:这个格式实在方法内的,表示当前代码手动抛出一个异常,下面的代码不用再执行了
public class test2 {
public static void main(String[] args) {
System.out.println("善良");
System.out.println("上进");
System.out.println("积极");
System.out.println("阳光");
throw new RuntimeException();
//当代执行到这时,就创建了一个异常对象,该异常创建后,暂时没有手动处理,抛给了调用者处理 下面的代码不会执行了
System.out.println("消极");
}
}
throws和throw的区别
throws用在方法声明后边,跟的是异常类名,表示声明异常,调用该方法有可能会出现这样的异常
throw 用在方法体内,跟的是异常对象名,表示手动抛出异常对象,由方法体的语句处理
抛出异常的意义
1.在方法中,由于传递的参数有误,没有继续运行下去的意义了,则采取抛出处理,表示让该方法结束运行
2.告诉调用者方法出现了问题
public class test3 {
public static void main(String[] args) {
//int[] arr={1,2,3,4,5};
int[] arr=null;
//会接收到一个异常,自己未处理,还是交给虚拟机处理
printArr(arr);
}
private static void printArr(int[] arr) {
if (arr==null){
System.out.println("参数不能为null");//调用者不知道是否成功打印
throw new NullPointerException();
//当参数为null的时候 手动创建了一个异常对象,抛给了调用者。
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
}
异常处理方式-----try...catch....
格式:
try{
可能出现异常的代码
}catch(异常类名 变量名){
异常的处理代码;
}
好处:可以让代码继续运行
public class test3 {
public static void main(String[] args) {
int[] arr=null;
try{
//有可能发现异常的代码
printArr(arr);
}catch (NullPointerException e){
//对代码的处理方式
System.out.println("参数不能未null");
}
System.out.println("一闪一闪亮晶晶");//可以运行 说明try catch不会让虚拟机中断运行
}
private static void printArr(int[] arr) {
if (arr==null){
throw new NullPointerException();
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
}
如果try中没有遇到问题,会把try中所有代码全部执行完毕,不会执行catch里的代码
如果try中遇到了代码,try下边的代码不会执行,会直接跳到catch语句中,当catch中的语句全部执行完毕,继续执行下边的代码
如果出现的问题没有被捕获 比如代码异常时空指针 但是catch里边的异常处理是解析异常 就会自己处理,如果我们没有自己处理的代码,就会交给虚拟机,将错误信息打印再控制台
同时有多个异常的话,就
try{
可能出现异常的代码
}catch(异常类型 变量名){
解决异常代码;
}catch(异常类型 变量名){
解决异常代码;
}
就是再加一个catch,如果多个异常之间存在子父类的关系,那么父类一定要写在下边
可能有点人认为写一个总异常,Exception 就可以包含所有的异常了,逻辑上是没问题的,代码也是没问题的
但是对于所有的异常只有一种处理结果,不太好,我们希望,针对不同的异常,又不同的处理结果