当前位置: 首页 > news >正文

有关Java中的异常和异常处理

学习目标

  1. 掌握异常的两大分类
  2. 掌握异常的处理
  3. 掌握自定义异常

1.概念

引入(了解):Java语言具备健壮性:
● 1. “异常处理机制”: 一段程序报错了 在我们处理的前提下 不影响其他程序的正常的执行。
● 2. GC 垃圾处理器 : garbage collection 回收无用的引用关联的对象。

程序报错了 ----> bug
● 1. 错误类型 Error
● 2. 异常类型 Exception
● 以上两者都是程序在运行期间出现的不正常的现象。
● 错误是处理不了的,要么改机器配置 要么改动源码;而异常是可以处理的,这就是本节学习的重点

通俗的说就是:程序执行中不正常的情况

2.Error

● java.lang.Error . 代表程序运行期间的任意一个错误。
● 这些错误一般都是非常严重的问题。一般与机器JVM有关系.
● 一般我们常见的是,java.lang.VirtualMachineError 抛出以表明Java虚拟机已损坏或已耗尽资源以使其继续运行。

层级结构:

public class Error  extends Throwable{}
//自动的拥有的父级提供的属性和方法
//创建子类对象 必然会执行父类的构造-----> Error类的构造方法  与Throwable 匹配

3.Exception

● java.lang.Exception. 程序运行期间 出现的不正常的现象。
● jvm规则: 可以使用异常处理机制处理异常。

层级结构:

public class Exception  extends Throwable{}

4.Error VS Exception

1.相同点

  1. 都继承了同一个父类 java.lang.Throwable
  2. 都是程序里面不正常的现象。

2.不同点

  1. 对于任意一个Error 不能处理。jvm默认不处理。一般都与jvm有关。
  2. 对于任意一个异常 都可以处理。jdk提供了异常处理机制,增强代码健壮性。
  3. 异常: 分为2类 编译时异常 运行时异常

5.异常的分类

  1. Throwable: 总父类

  2. Error: 表示错误

    • 特点为无法解决也无法提前避免
    • 通常由非常严重的底层错误或者硬件问题导致
  3. Exception: 表示异常

    • 特点为可以解决也可以提前避免

    • 通常由代码导致

    • 分类:

      • RuntimeException: 运行时异常, 也称为未检查异常|未检异常等

        • 特点为 编译成功,运行报错, 可以选择性处理

        • 常见的运行时异常:

     1. java.lang.ArithmeticException: 数学运算异常
     2. java.lang.NullPointerException: 空指针异常
     3. java.lang.StringIndexOutOfBoundsException: 字符串下标越界异常
     4. java.lang.ArrayIndexOutOfBoundsException: 数组下标越界异常
     5. java.lang.IndexOutOfBoundsException: 下标越界异常(底层中)
     6. java.lang.ClassCastException: 类型转换异常
     7. java.lang.NumberFormatException: 数据类型转换异常
     8. java.util.ConcurrentModificationException: 并发修改异常(集合指针遍历)
         ...
  • 非运行时异常, 也称为已检查异常|已检异常等

    • 特点编译失败, 必须处理
    • 不是运行时异常, 一定是非运行时异常

6.异常处理

异常处理方式
● 捕捉处理异常 (积极处理)
● 上抛异常 (消极处理)

6.1 捕获异常

1.语法

try{
    //可能存在异常的代码
}catch(异常类名1 引用名){
    //异常的处理代码
}catch(异常类名2 引用名){
    //异常的处理代码
}..

1.1 语法1

 try{
      //有可能会出现异常的代码
      //对于程序员而言  不要把所有的代码放到try  区分稳定代码以及非稳定的代码
  }catch(捕获到具体异常类型 变量名称/异常引用/对象){// (形参) 
      //对异常引用/对象 进行处理
      //1. SOUT
      //2. 调用异常类型的功能方法
      //3. return
      //4. 使用日志框架将不同级别的信息存储到不同的级别的日志文件中  最常用
      //5. 异常信息传递
      // 5.1 将子级异常类型的信息传递到父级  Casued by 引起异常的根本原因是原因
      // 5.2 分层开发:  dao--->service---->controller (SpringMVC的框架对异常进行全局处理)
      //6.一些业务逻辑....
  }finally{
     //不管程序是否存在异常  finally代码块的逻辑肯定是要执行的
     //1.释放物理资源  关闭一些资源
      //Scanner.close()
      //2. 在线程里面  使用锁机制实现线程安全  先上锁  后面要解锁
  }  

1.2 语法2

try{
    
}catch(){
    
} 

1.3 语法3

try{
    
}catch(){
    
}catch(){
    
}  
.....
//可以有多个catch块  
    
try{
    
}catch(异常类型1 | 异常类型2| ... 变量){
    
}    

1.4 语法4

try{
    
}finally{
    
}  
//先上锁  后面要解锁

2 使用

以处理运行时异常为例。代码演示使用方法,用于理解,并不特别规范

2.1 try…catch…finally

public static void main(String[] args) {

        //异常处理机制: 一段程序报错了  不影响其他程序正常执行
        //对运行时异常执行处理
        //try...catch...finally

        try {
            //有可能会出现异常逻辑
            System.out.println(3 / 0);
            //测试遍历数组元素
            int[] array = {1, 2, 3, 4};
            for (int num : array) {
                System.out.println(num);
            }
        } catch (ArithmeticException e) {//捕获到具体的异常类型  try里面有可能出现的异常
            System.out.println("除数不能为0");
            //在catch里面  一定要编写一些逻辑代码  sout
        } finally {
            //可以使用  可以省略finally
            System.out.println("finally..............");
        }

        //在try  异常之后的代码 不会执行的(从上到下)
        //在一个线程中  出现了异常 线程终止了  异常之后的代码 不执行了
    }

2.2 try…catch…catch

public static void main(String[] args) {

        //使用异常处理机制
        //1.可以使用多个catch块捕获不同的异常类型
        //2.在最后一个catch块中使用父级维护 捕获没有具体捕获到异常类型(多态)  从小到大
        //3.在多个catch块中  catch块的逻辑有且只允许一个(try第一次抛出的异常)
        try {
            String str = null;
            System.out.println(str.equals("hello"));//抛出异常
            System.out.println("1111111111111111111111");
            System.out.println(3 / 0);
        } catch (ArithmeticException e) {
            System.out.println("除数不能为0");
        } catch (NullPointerException e) {
            System.out.println("变量值为null");
        } catch (RuntimeException e) {
            System.out.println("程序出错了...");
        }
        System.out.println("----------------------");

        //1. 可以使用1个catch语句块替换多个catch
        //2. 使用| 异常类型必须是同级别的
        try {
            String str = null;
            System.out.println(str.equals("hello"));//抛出异常
            System.out.println("1111111111111111111111");
            System.out.println(3 / 0);
        } catch (NullPointerException | ArithmeticException | ArrayIndexOutOfBoundsException e) {
            System.out.println("程序出错了...");
        } catch (RuntimeException e) {

        }
    }

2.3 try…finally

private static void demo3() {
    Lock lock = new ReentrantLock();
    try {
        lock.lock();//上锁了
        //jdshdgsdshdshgds
        //jdshdgsdshdshgds
        //jdshdgsdshdshgds
        //jdshdgsdshdshgds
        //编写程序  就有可能会出现运行时异常----> 不做处理----> 当前线程终止了
    } finally {
        lock.unlock();
    }
}
private static void demo1() {
    //try....finally
    Scanner input = new Scanner(System.in);
    try {
        int num = input.nextInt();//不需要做任何处理----> 运行时异常  不能处理
    } finally {
        System.out.println("1111111111111111111");
        input.close();//不管上面的代码是否存在异常 都要释放资源
    }

    //jdk1.7+ 提供了更加优雅的方式  释放流资源
    //try....with...resources  自动的调用close  前提: 类型必须实现Closeable
    //try(){
    // }

    System.out.println("22222222222222222");
}

private static void demo2() {
    Scanner input = new Scanner(System.in);
    Scanner input1 = new Scanner(System.in);
    MyClass myClass = new MyClass();
    //try(引用1;引用2)
    try (input; input1; myClass) {//自动的调用input/input1的close
        int num = input.nextInt();
    }
}

2.4 catch块

需要了解,在catch代码块中,我们可以编写什么样的代码,对异常对象进行相关的处理?

private static void demo1() {
    try {
        //有可能会出现异常逻辑
        System.out.println(3 / 0);
    } catch (ArithmeticException e) {

        //对异常对象/引用执行处理
        //System.out.println("报错了.....");
        //1. sout
        //2. 调用异常类型的功能方法  e
        //System.err.println("获得异常的详细的字符串:"+e.getMessage());
        //e.printStackTrace();
        //3. return  方法有返回值类型的方法
        // return;
        //4. 使用日志组件  将异常信息写入具体不同级别的文件中  info  debug error  warn fatal  学会在服务器中查看日志文件内容
        //Log4j2 logback
        //5.进行异常信息传递  Caused by  throw将低级别的异常引用传递到高级别的异常对象
        //throw 手动抛出具体的异常对象----> new ----> throw new 异常类型构造;
        //RuntimeException exception = new RuntimeException("异常信息传递了",e);
        throw new RuntimeException("除数为0",e);//手动产生异常  当前线程就终止了
        //e.printStackTrace();

        //6.不同业务代码实现
    }
    System.out.println("---------------------");
    //System.out.println(3/0);
}

2.5 finally中禁止使用return

private static int demo2() {
    try {
        System.out.println(3 / 0);
        return 100;//当前demo2就结束
    } catch (RuntimeException e) {
        System.out.println("报错了....");
        e.printStackTrace();
    } /*finally {
            return 300; //都会执行  禁止在finally中使用return
        }*/
    return 200;
}

6.2 抛出异常 throws

● 消极处理异常的方式。 并没有真正的处理异常
● 使用throws关键字把异常类型抛出给上级/调用者。谁是上层调用者? 哪个方法在调用这个方法,那个方法就是上层调用者
● 在方法签名后面 使用throws关键字抛出多个异常类型。

  1. 上抛异常 (消极处理)

    • 思路: 自身不解决问题, 将问题上抛至调用者, 由调用者承担处理异常的责任
   访问修饰符 返回值类型 方法名(形参列表) throws 异常类名1,异常类名2,.. {
       
   }
  • 特点: 只能暂时规避处理异常的责任, 无法根治问题, 如果所有方法都未解决异常, 则最终会上抛至虚拟机, 程序终止

  • 使用场景:

    • 调用抛出非运行时异常的方法时, 暂时规避编译报错使程序运行
    • 约束调用者必须处理某些异常
  • 使用细节:

    • 父类类名可以兼容处理子类异常对象
    • 调用者需要处理的异常类型由被调用方法throws上抛的类型决定
    • 可以上抛方法内并未存在的异常类型

7.throw

  1. throw是抛出的意思。
  2. 在方法体里面 使用throw 抛出异常对象。
  3. throw不是处理异常。throw是产生异常的。
  4. throw new 异常类构造;
  5. 一般经常作为条件预判使用,或者在catch块里面 实现异常对象传递。
  6. 在方法体里面 遇见throw 代表当前线程终止。

throw与throws的区别总结

特性throwthrows
位置在方法体内部使用在方法签名后面使用
语法throw new ExceptionType("Error message");void methodName() throws ExceptionType1, ExceptionType2 { ... }
作用用于抛出一个具体的异常对象用于声明方法可能抛出的异常类型
使用场景当程序遇到某种错误条件时,手动抛出异常当方法内部可能抛出异常,但不处理时,声明该方法可能抛出的异常类型
异常处理直接产生异常,通常需要在方法内部处理或由调用者处理声明异常,调用者需要处理或继续声明抛出

8.自定义异常

● jdk中 提供了很多异常类型。但是每个异常都是满足特定的场景。解决特定的问题。
● 在开发中 有很多业务 出现的问题, jdk没有提供对应的异常类型解决。如果不在乎名称的问题,直接使用jdk的内置异常类型也是可以的。但是总之不是很优雅。
● 假如用户支付余额不足异常。如果使用NPE等异常,就显得不那么合适。因此,我们有需要自定义一些和业务相关的异常类型,满足个性化设计。

  1. 自定义运行时异常: 继承RuntimeException, 书写构造
   /**
    * 自定义运行时异常
    */
   public class MyRuntimeException extends RuntimeException {
       //无参构造
       public MyRuntimeException(){}
   
       //有参构造
       public MyRuntimeException(String message) {
           super(message);
       }
   }
  1. 自定义非运行时异常: 继承Exception, 书写构造
   
   /**
    * 自定义非运行时异常
    */
   public class MyException extends Exception {
       //无参构造
       public MyException(){}
   
       //有参构造
       public MyException(String message) {
           super(message);
       }
   }

有参构造作用: 最终调用Throwable中的有参构造给detailMessage详细信息属性赋值 , 该属性的值可通过getMessage()获取

相关文章:

  • 图神经网络怎么和LLM结合
  • Docker 入门与实战:从安装到容器管理的完整指南
  • nlp|微调大语言模型初探索(1),LLaMA-Factory
  • 用deepseek学大模型05-线性回归
  • UnityRecorder导出带透明通道的视频和图片
  • Java 版本 24 性能更新:更快、更智能
  • 高效构建与配置高可用负载均衡集群:从理论到实践的全面实施
  • WordPress 角标插件:20 种渐变色彩搭配,打造专属菜单标识
  • LeetCode每日精进:142.环形链表II
  • 应用分层、三层架构和MVC架构
  • 容器运行常见数据库
  • 使用 IntersectionObserver 实现懒加载和无限滚动
  • 静态页面在安卓端可以正常显示,但是在ios打开这个页面就需要刷新才能显示全图片
  • Dify+Ollama+DeepSeek部署本地大模型+知识库搭建
  • CSS flex布局 列表单个元素点击 本行下插入详情独占一行
  • BMS项目-面试及答疑整理
  • 【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发三
  • Linux:线程的互斥与同步
  • Vmware ubuntu22.04 虚拟机 连接windows主机虚拟串口
  • 5G时代的运维变革与美信监控易的深度剖析
  • 11家券商一季度净利翻番:9家利润超20亿,国泰海通居首
  • 北部艳阳高照、南部下冰雹,五一长假首日上海天气很“热闹”
  • 美国务院宣布新一轮与伊朗相关的制裁
  • 央行4月开展12000亿元买断式逆回购操作
  • 澎湃回声丨23岁小伙“被精神病”8年续:今日将被移出“重精”管理系统
  • 圆桌|如何应对特朗普政府的关税霸凌?一种联合国视角的思考