Java异常你还没有了解吗?

news2024/12/23 22:34:17

🤷‍♀️🤷‍♀️🤷‍♀️ 今天和大家一起学习一下Java中的异常!

清风的CSDN博客个人主页

🌂c/java领域新星创作者

🎉欢迎👍点赞✍评论❤️收藏

😛😛😛希望我的文章能对你有所帮助,有不足的地方还请各位看官多多指教,大家一起学习交流!

动动你们发财的小手,点点关注点点赞!在此谢过啦!哈哈哈!😛😛😛

 


目录

 一、异常的概念与体系结构

1.1异常的概念

1.1.1算术异常 

1.1.2数组越界异常

1.1.3空指针异常

1.2异常的体系结构 

 1.3异常的分类

1.3.1编译时异常

1.3.2运行时异常 

 二、异常的处理

2.1防御式编程

2.1.1 LBYL事前防御型

2.1.2EAFP:事后认错型  

2.2异常的抛出 

 2.3异常的捕获

2.3.1异常声明throws

2.3.2try-catch捕获并处理 


 

 一、异常的概念与体系结构

1.1异常的概念

在生活中,一个人表情痛苦,出于关心,可能会问:你是不是生病了,需要我陪你去看医生吗?

 

在程序中也是一样,程序猿是一帮办事严谨、追求完美的高科技人才。在日常开发中,绞尽脑汁将代码写的尽善尽美,在程序运行过程中,难免会出现一些奇奇怪怪的问题。有时通过代码很难去控制,比如:数据格式不对、网络不通畅、内存报警等。

Java中,将程序执行过程中发生的不正常行为称为异常。比如下面的代码: 

1.1.1算术异常 

System.out.println(10 / 0);
// 执行结果
Exception in thread "main" java.lang.ArithmeticException: / by zero

1.1.2数组越界异常

int[] arr = {1, 2, 3};
System.out.println(arr[100]);
// 执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100

1.1.3空指针异常

int[] arr = null;
System.out.println(arr.length);
// 执行结果
Exception in thread "main" java.lang.NullPointerException
从上述过程中可以看到,java中不同类型的异常,都有与其对应的类来进行描述

1.2异常的体系结构 

异常种类繁多,为了对不同异常或者错误进行很好的分类管理, Java 内部维护了一个异常的体系结构:

从上图中可以看到:
1. Throwable:是异常体系的顶层类,其派生出两个重要的子类, ErrorException。
2. Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表:StackOverflowError和OutOfMemoryError,一旦发生回力乏术。
3. Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说的异常就是Exception。

 1.3异常的分类

异常可能在编译时发生,也可能在程序运行时发生,根据发生的时机不同,可以将异常分为:

1.3.1编译时异常

在程序编译期间发生的异常,称为编译时异常,也称为受检查异常 (Checked Exception)。
public class Person {
    private String name;
    private String gender;
    int age;
    // 想要让该类支持深拷贝,覆写Object类的clone方法即可
    @Override
    public Person clone() {
    return (Person)super.clone();
   }
}
编译时报错:
Error:(17, 35) java: 未报告的异常错误java.lang.CloneNotSupportedException; 必须对其进行捕获或声明以便抛出

因为在定义Person类时,并没有实现克隆接口,因此会抛出不支持克隆异常。

1.3.2运行时异常 

          在程序执行期间发生的异常,称为 运行时异常 ,也称为 非受检查异常 (Unchecked Exception)
RunTimeException以及其子类对应的异常,都称为运行时异常 。比如: NullPointerException、
ArrayIndexOutOfBoundsException、 ArithmeticException。
  • 注意:编译时出现的语法性错误,不能称之为异常。例如将 System.out.println 拼写错了, 写成了system.out.println.。此时编译过程中就会出错, 这是 "编译期" 出错。而运行时指的是程序已经编译通过得到class 文件了, 再由 JVM 执行过程中出现的错误。

 二、异常的处理

2.1防御式编程

错误在代码中是客观存在的, 因此我们要让程序出现问题的时候及时通知程序猿 .。
主要的方式:

2.1.1 LBYL事前防御型

boolean ret = false;
ret = 登陆游戏();
if (!ret) {
处理登陆游戏错误;
return;
}
ret = 开始匹配();
if (!ret) {
处理匹配错误;
return;
}
ret = 游戏确认();
if (!ret) {
处理游戏确认错误;
return;
}
ret = 选择英雄();
if (!ret) {
处理选择英雄错误;
return;
}
ret = 载入游戏画面();
if (!ret) {
处理载入游戏错误;
return;
}
......
缺陷:正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱。

2.1.2EAFP:事后认错型  

try {
登陆游戏();
开始匹配();
游戏确认();
选择英雄();
载入游戏画面();
...
} catch (登陆游戏异常) {
处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}
....
优势:正常流程和错误流程是分离开的, 程序员更关注正常流程,代码更清晰,容易理解代码
异常处理的核心思想就是 EAFP。
Java中, 异常处理主要的 5 个关键字: throw try catch final throws

2.2异常的抛出 

      在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者,比如:参数检测。在Java 中,可以借助 throw 关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:
throw new XXXException("异常产生的原因");

 下面是一个抛出异常的实例代码:

public static int getElement(int[] array, int index){
    if(null == array){
         throw new NullPointerException("传递的数组为null");
      }
    if(index < 0 || index >= array.length){
         throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");
      }
     return array[index];
}
public static void main(String[] args) {
      int[] array = {1,2,3};
      getElement(array, 3);
}

注意事项:

  • throw必须写在方法体内部
  • 抛出的对象必须是Exception 或者 Exception 的子类对象
  • 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
  • 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
  • 异常一旦抛出,其后的代码就不会执行

 2.3异常的捕获

异常的捕获,也就是异常的具体处理方式,主要有两种:异常声明 throws 以及 try-catch 捕获处理。

2.3.1异常声明throws

处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助 throws 将异常抛给方法的调用者来处理。即 当前方法不处理异常,提醒方法的调用者处理异常。

 

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

下面看一个实例代码:

需求:加载指定的配置文件 config.ini
  public class Config {
     File file;
  /*
   FileNotFoundException : 编译时异常,表明文件不存在
   此处不处理,也没有能力处理,应该将错误信息报告给调用者,让调用者检查文件名字是否给错误了
  */
  public void OpenConfig(String filename) throws FileNotFoundException{
     if(filename.equals("config.ini")){
            throw new FileNotFoundException("配置文件名字不对");
         }
      // 打开文件
     }
  public void readConfig(){
    }
}

注意事项:

  • throws必须跟在方法的参数列表之后
  •  声明的异常必须是 Exception 或者 Exception 的子类
  • 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可。

下面是实例代码: 

 public class Config {
      File file;
      // public void OpenConfig(String filename) throws IOException,FileNotFoundException{
      // FileNotFoundException 继承自 IOException
  public void OpenConfig(String filename) throws IOException{
      if(filename.endsWith(".ini")){
           throw new IOException("文件不是.ini文件");
       }
      if(filename.equals("config.ini")){
           throw new FileNotFoundException("配置文件名字不对");
       }
       // 打开文件
   }
   public void readConfig(){
   }
}
  •  调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出
public static void main(String[] args) throws IOException {
    Config config = new Config();
    config.openConfig("config.ini");
}

 将光标放在抛出异常方法上,alt + Insert 快速 处理:

2.3.2try-catch捕获并处理 

throws 对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch
语法格式:
try{
   // 将可能出现异常的代码放在这里
  }catch(要捕获的异常类型 e){
   // 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中 
     抛出异常的基类时,就会被捕获到
    // 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
  }[catch(异常类型 e){
   // 对异常进行处理
  }finally{
     // 此处代码一定会被执行到
   }]
   // 后序代码
   // 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
   // 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行
注意:
1. []中表示可选项,可以添加,也可以不用添加
2. try中的代码可能会抛出异常,也可能不会

 下面是一个实例代码:

需求:读取配置文件,如果配置文件名字不是指定名字,抛出异常,调用者进行异常处理
public class Config {
    File file;
    public void openConfig(String filename) throws FileNotFoundException{
           if(!filename.equals("config.ini")){
                   throw new FileNotFoundException("配置文件名字不对");
            }
    // 打开文件
     }
    public void readConfig(){
     }
    public static void main(String[] args) {
                   Config config = new Config();
     try {
          config.openConfig("config.txt");
          System.out.println("文件打开成功");
         } catch (IOException e) {
            // 异常的处理方式
            //System.out.println(e.getMessage()); // 只打印异常信息
            //System.out.println(e); // 打印异常类型:异常信息
              e.printStackTrace(); // 打印信息最全面
        }
      // 一旦异常被捕获处理了,此处的代码会执行
          System.out.println("异常如果被处理了,这里的代码也可以执行");
    }
}
关于异常的处理方式:
1.异常的种类有很多, 我们要根据不同的业务场景来决定。
2.对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果。
3.对于不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿。
4.对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试。
5.在我们当前的代码中采取的是经过简化的第二种方式。我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置.。以后在实际工作中我们会采取更完备的方式来记录异常信息。

注意事项:

  • try块内抛出异常位置之后的代码将不会被执行
  • 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也不会被处理,继续往外抛,直到JVM收到中断程序----异常是按照类型来捕获的
     

比如下面的代码:

public static void main(String[] args) {
   try {
        int[] array = {1,2,3};
        System.out.println(array[3]); // 此处会抛出数组越界异常
   }catch (NullPointerException e){ // 捕获时候捕获的是空指针异常--真正的异常无法被捕获到
           e.printStackTrace();
        }
      System.out.println("后序代码");
   }
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 at day20210917.ArrayOperator.main(ArrayOperator.java:24)
  •  try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获

例如:

public static void main(String[] args) {
   int[] arr = {1, 2, 3};
   try {
         System.out.println("before");
         // arr = null;
         System.out.println(arr[100]);
         System.out.println("after");
       } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("这是个数组下标越界异常");
                e.printStackTrace();
       } catch (NullPointerException e) {
                System.out.println("这是个空指针异常");
                e.printStackTrace();
       }
       System.out.println("after try catch");
}
  •  如果多个异常的处理方式是完全相同, 也可以写成这样:
catch (ArrayIndexOutOfBoundsException | NullPointerException e) {
...
}
  •  如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误:
public static void main(String[] args) {
     int[] arr = {1, 2, 3};
     try {
            System.out.println("before");
            arr = null;
            System.out.println(arr[100]);
            System.out.println("after");
         } catch (Exception e) { // Exception可以捕获到所有异常
            e.printStackTrace();
         } catch (NullPointerException e){ // 永远都捕获执行到
            e.printStackTrace();
         }
         System.out.println("after try catch");
}
Error:(33, 10) java: 已捕获到异常错误java.lang.NullPointerException
  •  可以通过一个catch捕获所有的异常,即多个异常,一次捕获(不推荐)
public static void main(String[] args) {
      int[] arr = {1, 2, 3};
      try {
              System.out.println("before");
              arr = null;
              System.out.println(arr[100]);
              System.out.println("after");
          } catch (Exception e) {
              e.printStackTrace();
          }
         System.out.println("after try catch");
}

 由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常。

注意:catch 进行类型匹配的时候, 不光会匹配相同类型的异常对象, 也会捕捉目标异常类型的子类对象.。如刚才的代码, NullPointerException 和 ArrayIndexOutOfBoundsException 都是 Exception 的子类, 因此都能被捕获到。


🎉好啦,今天的分享就到这里!!

创作不易,还希望各位大佬支持一下!

👍点赞,你的认可是我创作的动力!

⭐收藏,你的青睐是我努力的方向!

✏️评论:你的意见是我进步的财富!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1174382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaScript】window 对象、location 对象、navigator 对象和 history 对象

1. window 对象 BOM (Browser Object Model ) 是浏览器对象模型&#xff1a; window对象是一个全局对象&#xff0c;也可以说是JavaScript中的顶级对象像document、alert()、console.log()这些都是window的属性&#xff0c;基本BOM的属性和方法都是window的所有通过var定义在全…

【Java 进阶篇】JSP 简单入门

在现代Web开发中&#xff0c;JavaServer Pages&#xff08;JSP&#xff09;是一项非常重要的技术。JSP允许开发者将Java代码嵌入HTML页面&#xff0c;以实现动态内容的生成和呈现。本文将详细介绍JSP的概念、原理以及如何使用JSP来构建Web应用程序。 第一部分&#xff1a;JSP …

基于Google Colaboratory安装Go语言编译器操作流程

文章目录 1. 什么是Google Colaboratory2. 访问Google Colaboratory3. 创建新的笔记本4.【方法①】使用apt命令安装golang5.【方法②】使用Go安装包安装golang6. 参考链接 1. 什么是Google Colaboratory Colab是一种托管的笔记本电脑服务&#xff0c;不需要安装即可使用&#x…

Perl安装教程

1. perl简介 Perl 是 Practical Extraction and Report Language 的缩写&#xff0c;可翻译为 “实用报表提取语言”。Perl 是高级、通用、直译式、动态的程序语言。Perl 最初的设计者为拉里沃尔&#xff08;Larry Wall&#xff09;&#xff0c;于1987年12月18日发表。Perl 借…

PCTA认证考试-01_TiDB数据库架构概述

TiDB 数据库架构概述 一、学习目标 理解 TiDB 数据库整体结构。了解 TiDB Server&#xff0c;TiKV&#xff0c;TiFlash 和 PD 的主要功能。 二、TiDB 体系架构 1. TiDB Server 2. TiKV OLTP 3. Placement Driver 4. TiFlash OLAP OLTPOLAPHTAP

【Go 编程实践】从零到一:创建、测试并发布自己的 Go 库

为什么需要开发自己的 Go 库 在编程语言中&#xff0c;包&#xff08;Package&#xff09;和库&#xff08;Library&#xff09;是代码组织和复用的重要工具。在 Go 中&#xff0c;包是代码的基本组织单位&#xff0c;每个 Go 程序都由包构成。包的作用是帮助组织代码&#xf…

高等数学教材重难点题型总结(十二)无穷级数

最后一更&#xff01;原谅博主已经开始瞎写字了&#xff0c;最近压力太大&#xff0c;以后有时间用mathPix打出来&#xff0c;看起来更舒适一些~ 高数最后一章&#xff0c;重点在于审敛法和求解幂级数的收敛半径~ 高数基础笔记全部更新完毕&#xff0c;共12*336期&#xff0c…

【qemu逃逸】华为云2021-qemu_zzz

前言 虚拟机用户名&#xff1a;root 无密码 设备逆向 经过逆向分析&#xff0c;可得实例结构体大致结构如下&#xff1a; 其中 self 指向的是结构体本身&#xff0c;cpu_physical_memory_rw 就是这个函数的函数指针。arr 应该是 PCI 设备类结构体没啥用&#xff0c;就直接用…

动态规划算法实现0-1背包问题Java语言实现

问题介绍&#xff1a; 动态规划算法&#xff1a; 动态规划&#xff08;Dynamic Programming&#xff09;是一种解决多阶段决策问题的优化算法。它通过将问题分解为一系列子问题&#xff0c;并利用子问题的解来构建更大规模问题的解&#xff0c;从而实现对整个问题的求解。 动态…

五子棋对战测试报告

目录 一、项目背景 二、项目功能 三、功能测试 1、注册页面测试 测试用例 测试结果 测试总结 2、登录页面测试 测试用例 测试结果 测试总结 3、游戏大厅页面测试 测试用例 测试结果 测试总结 4、游戏房间页面测试 测试用例 测试结果 测试总结 一、项目背景 …

物联网AI MicroPython传感器学习 之 无源蜂鸣器

一、产品简介 蜂鸣器是一种将音频信号转化为声音信号的发音器件传感器&#xff0c;通过利用压电效应原理&#xff0c;当对其施加交变电压时产生机械振动。应用场景&#xff1a;在家用电器、电子玩具、游戏机等场景下都得到普遍应用&#xff0c;通过设置不同的频率&#xff0c;…

Linux下yum源配置实战

一、Linux下软件包的管理 1、软件安装方式 ① RPM包管理&#xff08;需要单独解决依赖问题&#xff09; ② YUM包管理&#xff08;需要有网络及YUM仓库的支持&#xff0c;会自动从互联网下载软件&#xff0c;自动解决依赖&#xff09; ③ 源码安装&#xff08;安装过程比较…

前端面试题之CSS篇

1、css选择器及其优先级 标签选择器: 1类选择器、属性选择器、伪类选择器&#xff1a;10id选择器&#xff1a;100内联选择器&#xff08;style“”&#xff09;&#xff1a;1000!important&#xff1a;10000 2、display的属性值及其作用 属性值作用none元素不显示&#xff0c…

数据分析实战 | 关联规则分析——购物车分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据预处理 七、生成频繁项集 八、计算关联度 九、可视化 一、数据及分析对象 数据集链接&#xff1a;Online Retail.xlsx 该数据集记录了2010年12月01日至2011年12月09日…

【深蓝学院】手写VIO第8章--相机与IMU时间戳同步--作业

0. 题目 1. T1 逆深度参数化时的特征匀速模型的重投影误差 参考常鑫助教的答案&#xff1a;思路是将i时刻的观测投到world系&#xff0c;再用j时刻pose和外参投到j时刻camera坐标系下&#xff0c;归一化得到预测的二维坐标&#xff08;这里忽略了camera的内参&#xff0c;逆深…

力扣刷题之优先队列

前言&#xff1a;优先队列底层是由大根堆或小根堆数据结构实现的。 前K个高频元素 347. 前 K 个高频元素 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: …

基于LDA主题+协同过滤+矩阵分解算法的智能电影推荐系统——机器学习算法应用(含python、JavaScript工程源码)+MovieLens数据集(四)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据爬取及处理2. 模型训练及保存3. 接口实现4. 收集数据5. 界面设计 系统测试相关其它博客工程源代码下载其它资料下载 前言 前段时间&#xff0c;博主分享过关于一篇使用协同过滤算法进行智能电影推荐系统的博…

CCF-CSP真题《202305-5 闪耀巡航》思路+python,c++满分题解

想查看其他题的真题及题解的同学可以前往查看&#xff1a;CCF-CSP真题附题解大全 试题编号&#xff1a;202305-5试题名称&#xff1a;闪耀巡航时间限制&#xff1a;5.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 问题描述 西西艾弗岛旅游公司最近推出了一系列环绕西西艾…

周报4_YMK

FlashAttention 硬件知识 以 A100 (40GB HBM) 为例&#xff0c;下面显示其内存层次结构的粗略图。SRAM内存分布在108个流式多处理器(SMs)上&#xff0c;每个处理器192KB。片上SRAM比HBM快得多&#xff0c;但比HBM小得多&#xff0c;在计算方面&#xff0c;使用Tensor Core的B…

【ARFoundation学习笔记】ARFoundation基础(上)

写在前面的话 本系列笔记旨在记录作者在学习Unity中的AR开发过程中需要记录的问题和知识点。难免出现纰漏&#xff0c;更多详细内容请阅读原文。 本文从原文第二章开始 文章目录 ARFoundation的体系Subsystem的使用跟踪子系统 ARSession & AR Session OriginARSessionARSe…