java 异常

异常

  • 异常指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。

  • 异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。

  • 异常报错结构为栈结构,又称异常栈。后执行的先报错,先执行的后报错。


异常分类

在这里插入图片描述

Throwable 体系:异常的根类java.lang.Throwable

  • Errorjava.lang包下,系统异常,JVM退出,代码无法控制等。

  • Exceptionjava.lang包下,程序异常,可以通过代码纠正,使程序继续运行

    • Checked 异常:编译时期异常,可能会在运行时发生,编译期必须处理(调用方法抛出,需要显式捕获或抛出),否则程序不能通过编译。(如日期解析异常ParseException)

    • Runtime 异常:运行时期异常,运行时异常,编译阶段不会报错。

      • 数组索引越界异常:ArrayIndexOutOfBoundsException
      • 空指针异常 :NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
      • 类型转换异常:ClassCastException
      • 数学操作异常:ArithmeticException
      • 数字转换异常: NumberFormatException
方法描述
public void printStackTrace()打印异常的详细信息,开发调试常用
public String getMessage()获取发生异常的原因,用户提示常用
public String toString()获取异常的类型和异常描述信息,基本不用
  • printStackTrace()打印内容包括
    • 异常类型
    • 异常原因
    • 异常出现的位置
//getMessage()
date must not be null
//toString()
java.lang.NullPointerException: date must not be null
//printStackTrace()
java.lang.NullPointerException: date must not be null
	at java.base/java.util.Objects.requireNonNull(Objects.java:233)
	at java.base/java.util.Calendar.setTime(Calendar.java:1792)
	at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:978)
	at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:971)
	at java.base/java.text.DateFormat.format(DateFormat.java:378)
	at com.css.yang.studytest.Test.test(Test.java:15)
	at com.css.yang.studytest.Test.main(Test.java:21)

产生过程

  1. 默认会在出现异常的代码那里自动的创建⼀个异常对象:ArithmeticException。
  2. 异常会从方法中出现的点这里抛出给调用者
  3. 调用者最终抛出给 JVM 虚拟机。
  4. 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
  5. 直接从当前执行的异常点干掉当前程序。
  6. 后续代码没有机会执行了,因为程序已经死亡
class ArrayTools {
    // 对给定的数组通过给定的角标获取元素。
    public static int getElement(int[] arr, int index) {
        int element = arr[index];
        return element;
    }
}
public class ExceptionDemo {
    public static void main(String[] args) {
        int[] arr = { 34, 12, 67 };
        int num = ArrayTools.getElement(arr, 4);
        System.out.println("num=" + num);
        System.out.println("over");
    }
}

在这里插入图片描述


异常处理

编译时异常的处理形式有三种:

  • 出现异常直接抛出去给调用者,调用者也继续抛出去。
  • 出现异常自己捕获处理,不麻烦别人。
  • 前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。

抛出异常(throw)
  • 判断数据合法性,若不合法,则在方法内抛出指定异常(自定义提示信息)
  • 抛出编译时异常时,必须在方法签名上用 throws 显式声明,由调用者处理
  • 抛出运行时异常则不做强制要求
  • 抛出异常时,若调用者不做处理,则继续往上层抛出,直到抛给 jvm 。jvm 会尝试去寻找能够处理该异常的异常处理器(try-catch),若找到则会将异常交给处理器进行处理,否则,jvm 会打印异常堆栈信息并终止该程序
  • 如果父类抛出了多个异常,子类覆盖父类方法时,若要抛出异常,只能抛出相同的异常或者是他的子集。
  • 父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
  • 推荐底层异常统一抛出,由外层集中处理异常

抛出格式

throw new 异常类名(参数);
public class ThrowDemo {
    //根据索引找到数组中对应的元素
    public static int getElement(int[] arr,int index){ 
        if(index<0 || index>arr.length-1){
             throw new ArrayIndexOutOfBoundsException("哥们,下标越界了。。。");
        }
        int element = arr[index];
        return element;
    }
    public static void main(String[] args) {
        //创建一个数组 
        int[] arr = {2,4,52,2};
        //根据索引找对应的元素 
        int index = 4;
        int element = getElement(arr, index);
		//输出
        System.out.println(element);
        System.out.println("over");
    }
}

声明异常(throws)
  • 用在方法签名上,显式声明方法中可能出现的异常,由调用者处理
  • 若方法签名中声明了编译时异常,则强制要求调用者处理该异常
  • 若方法签名中声明了运行时异常,则不强制要求调用者处理该异常
  • 方法内若抛出了编译时异常,并没有捕获处理,则强制要求在方法签名中声明该异常
  • 方法内若抛出了运行时异常,并没有捕获处理,则不强制要求在方法签名中声明该异常
  • 这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。

声明格式

修饰符 返回值类型 方法名(参数) throws 异常类名1, 异常类名2, ... { ... }	

捕获异常(try-catch)
  • 监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。

  • 发生异常的方法自己独立完成异常的处理,程序可以继续往下执行

  • 方法中可以多次捕获不同异常(多个try-catch语句),但推荐一次捕获,即放在一起捕获(一个try-catch),防止出现异常后,下面语句依然执行。

捕获格式

try{
     //编写可能会出现异常的代码
}catch(异常类型 e){
     //记录日志/打印异常信息/继续抛出异常
}

catch 语句

  • catch (ParseException e) {
        throw new RuntimeException(e);
    }
    

    将编译期异常转换成运行期异常处理,并将异常栈信息保存下来,抛给调用者,方便后续的调试和处理。

  • catch (ParseException e) {
        e.printStackTrace();
    }
    

    将异常信息直接打印到控制台上,一般用于调试和排查问题的过程中。

多个异常处理

  • 多次捕获,分别处理(多个try-catch)
  • 一次捕获,多次处理(多个catch)
  • 一次捕获,一次处理(catch中多种异常)

推荐第二种处理方式,格式如下:

try{
     //编写可能会出现异常的代码
}catch(异常类型A  e){  
     //记录日志/打印异常信息/继续抛出异常
}catch(异常类型B  e){
     //记录日志/打印异常信息/继续抛出异常
}

:这种异常处理方式,要求多个catch中的异常不能相同。若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。


finally

一些特定的代码无论异常是否发生,都需要执行。常用来关闭资源

使用格式

try {...} catch (Exception e) {...} finally {...}

:即使语句中有return也依然执行。只有在try或catch中调用退出 jvm 的相关方法(System.exit),finally才不会执行,否则finally永远会执行。


try-with-resource

JDK 7 和 JDK 9 中都简化了资源释放操作。

  • JDK 7

    try (定义流对象) {
    	可能出现异常的代码;
    } catch (异常类名 变量名) {
    	异常处理代码;
    }
    
  • JDK 9

    定义输入流对象;
    定义输出流对象;
    try (输入流对象;输出流对象) {
    	可能出现异常的代码;
    } catch (异常类名 变量名) {
    	异常处理代码;
    }
    

注意事项

  • 资源用完自动释放
  • ()中只能放置资源对象,否则报错
  • 资源对象是实现了CloseableAutoCloseable接口的类对象

自定义异常

可以根据自己业务的异常情况来定义异常类。例如年龄负数问题,考试成绩负数问题。

定义格式

  • 自定义编译时异常

    1. 定义⼀个异常类继承java.lang.Exception
    2. 重写构造器(空参构造和提示构造)
    3. 在出现异常的地方用throw new 自定义对象抛出

    作用:编译时异常是编译阶段就报错,提醒更加强烈,⼀定需要处理!!

  • 自定义运行时异常

    1. 定义⼀个异常类继承java.lang.RuntimeException
    2. 重写构造器(空参构造和提示构造)
    3. 在出现异常的地方用throw new 自定义对象抛出

    作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值