认识Java的异常

异常机制

异常机制指的是程序出现错误时,程序的处理方式。

程序的错误分为三种:

  • 编译错误:由于没有遵循对于语言的语法规则,编辑器可以自动发现并提示的错误位置和原因。
  • 逻辑错误:程序没有按照预期的顺序执行。
  • 运行时错误:程序执行过程中,运行环境发现不能执行的操作,而异常就是指的程序运行时发生的错误。

走进异常

例子:算数异常+数组下标越界异常+空指针异常

public static void main(String[] args) {System.out.println(10/0);    // 算数异常
// ----------------------------------------int[] a = {1,2,3,4,5};    // 数组下标越界异常System.out.println(a[10]);
// ----------------------------------------int[] a = null;    // 空指针异常System.out.println(a[0]);}

 上述的代码在分别运行时均会抛出异常,且抛出异常后不会去执行下面的代码。如下图

以空指针异常为例,根据空指针异常的源码,可以知道异常其实就是一个个类

异常的体系结构: 

在Java中,所有的异常都有一个共同的祖先:Throwable(可抛出),Throwable有两个子类,分别为Error(错误)和Exception(异常),它们两者的区别是:Error不能够被处理,但是Exception可以被程序本身所处理。

Error(错误):是程序无法处理的错误,表示运行程序中较严重的问题。大多数错误与代码的编写者执行的操作无关,而表示代码运行时JVM出现的问题。因此我们在编写程序时不必关心这一类错误。常见的有StackOverflowError(栈溢出),NOClassDefFoundError(类定义错误)

Exception(异常):是程序本身可以处理的异常。在编写程序时我们要尽可能的去处理这些异常。有一个重要的子类RuntimeException。它以及它的子类表示jvm常用操作引发的异常。例如开头提到的算数异常,数组越界异常以及空指针异常。主要分为两大类:运行时异常和编译时异常(非运行时异常)

  • 运行时异常:时RuntimeException类及其子类的异常,这些异常称为非受查异常,程序可以选择处理,或者不进行处理。一般是由程序的逻辑错误导致,例如:数组下标越界,在编写程序时,应当尽可能的避免这类情况的发生。
  • 编译时异常:RuntimeException以外的异常,这些都是必须在编译前必须处理的异常,如果不进行处理,那么编译时就不会通过。

通常,Java中的异常(Throwable)分为两大类:受查异常和非受查异常:

  • 受查异常:除了Error类和RunTimeException类及其子类以外的所有类,在编译期间抛出,如何不进行处理,代码不会通过编译,当程序出现这里异常,要么使用try-catch语句进行捕获,要么用throw进行抛出
  • 非受查异常:包括Error类和RunTimeException类及其子类,一般是对代码进行修改(因为大部分是代码本身的出错)而不是去捕获它们。

异常的处理

关键词throw:

异常可以通过jvm自动抛出,也可以通过程序员通过throw手动抛出。例如抛出一个自定义异常:

public class Main {public static void test(int a) {if(a == 1) {throw new ArithmeticException("a == 1");}}public static void main(String[] args) {test(1);}
}

表示如果是传入的是1,那么就会抛出算数异常(可以传参,也可以不传参),异常信息为a==1.

注意事项:

  1. throw必须写在方法体的内部。
  2. 抛出的对象必须是Exception或者Exception的子类对象。
  3. 如果抛出的是RunTimeException或者RunTimeException,则可以不用处理,直接交给jvm进行处理。
  4. 异常一旦抛出,后面的代码不会执行。

关键词throws:

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

throws其实并没有处理异常,只是告诉调用此方法可能会抛出相对应的异常,交给了此方法的调用者进行处理,如果不进行处理,不断的throws,知道交给jvm进行处理,此时程序就会终止
例如: throws CloneNotSupportedException就是声明main方法和clone方法可能会抛出的异常

class Person implements Cloneable {@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class test1 {public static void main(String[] args) throws CloneNotSupportedException {Person person = new Person();Person person1 = (Person) person.clone();}
}

注意:

  1. throws必须位于方法的参数列表之后
  2. throws后的异常必须是Exception类及其子类
  3. 如果throws语句异常存在父子关系,只需要保留父类即可
  4. throws并没有真正的处理异常,只是将异常抛出给上层的调用者,最终交给jvm处理

关键词:try-catch:

try{
        // 异常的代码
}catch(异常的类型 变量){

}

其中try内部写可能出现异常的代码,catch用于捕获指定的异常;如果try内部出现异常,catch进行捕获,捕获成功执行catch内部的代码,捕获失败,程序终止并报错。

public class Main {public static void test(int a) throws CloneNotSupportedException{if(a == 1) {throw new CloneNotSupportedException();}}public static void main(String[] args) {try {test(1);System.out.println("没有抛出异常");}catch (CloneNotSupportedException e) {System.out.println("捕获了异常");}System.out.println("程序到末尾");}
}

向test传参整形1,进入if语句,throw抛出异常,catch进行异常的捕获,最终执行打印:
捕获了异常,程序到末尾,但是如果注释掉if了的throw语句,那么就不会抛出异常,那么就不会被捕获,因此执行打印:没有抛出异常,程序到了末尾。


当打印了异常信息后,可能难以发现异常信息的出现位置,这是可以用到catch里面的变量信息e,利用e.printStackTrace()栈信息的打印,可以帮助追踪到出错位置;

public class Main {public static void test(int a) throws CloneNotSupportedException{if(a == 1) {throw new CloneNotSupportedException();}}public static void main(String[] args) {try {test(1);System.out.println("进入try");}catch (CloneNotSupportedException e) {System.out.println("捕获了异常");e.printStackTrace();}System.out.println("程序到末尾");}
}

由于PrintStackTrace打印逻辑不基于println,因此程序到末尾不是最后打印。

当一个程序可能出现多个异常时,需要多个catch语句进行捕获。

    public static void main(String[] args) {int[] arr = {1,2,3};try {System.out.println(arr[1]);arr = null;System.out.println(arr.length);}catch (ArrayIndexOutOfBoundsException e) {System.out.println("处理 ArrayIndexOutOfBoundsException 异常");e.printStackTrace();}catch (NullPointerException e) {System.out.println("处理 NullPointerException 异常");e.printStackTrace();}System.out.println("-----------------------------------");}

这里时空指针异常,用第二个catch进行捕获。

 但是不会一下子抛出多个异常,因为当捕获到一个异常后,catch进行处理,后面的异常不会被捕获

一些不规范的异常抛出

1.存在一个catch语句并且待捕获异常为Exception,通过一个catch捕获所有,这样子写不能搞清楚到底是抛出了那些异常。但是Exception可以兜底。

public static void main(String[] args) {int[] arr = {1,2,3};try {System.out.println(arr[4]);}catch (Exception e) {System.out.println("处理 Exception 异常");e.printStackTrace();}}// ----------------------------------------------------------public static void main(String[] args) {int[] arr = {1,2,3};try {System.out.println(arr[4]);}catch (NullPointerException e) {System.out.println("处理 NullPointerException 异常");e.printStackTrace();}catch (Exception e) {System.out.println("处理 Exception 异常,兜底");e.printStackTrace();}}

2.存在一个catch语句并且捕获多个异常,用|进行连接,和上述相同,分不清到底抛出什么异常

public static void main(String[] args) {int[] arr = {1,2,3};try {System.out.println(arr[4]);}catch (ArrayIndexOutOfBoundsException | NullPointerException e) {System.out.println("处理 ArrayIndexOutOfBoundsException | NullPointerException 异常");e.printStackTrace();}}

3.前面的catch捕获Exception,后面的catch捕获了Exception的子类

public static void main(String[] args) {int[] arr = {1,2,3};try {System.out.println(arr[4]);}catch (Exception e) {System.out.println("处理 Exception 异常");e.printStackTrace();}catch (NullPointerException e) {System.out.println("处理 NullPointerException 异常");e.printStackTrace();}}

总结:

  1. try块内出现异常位置后的语句不会被执行
  2. 抛出的异常与catch不匹配,一直向上抛出,直到抛给jvm进行处理
  3. try中多个异常可以用多个catch进行一一捕获,可以用Exception进行兜底,但是不推荐直接用Exception
  4. 当catch出现父子关系,子类在上,父类在下

关键字:finally

在编写代码的过程中,有些代码无论是否发生异常都需要被执行,比如程序中打开的资源:网络连接,数据库,在程序正常或者异常退出时,必须对资源进行回收,另外,异常会引发程序的跳转,导致语句无法执行,针对这些语句,Java提供了finally关键字,和try-catch组合为try-catch-finally进行一起使用

public static int getData() {Scanner sc = null;try {sc = new Scanner(System.in);int data = sc.nextInt();return data;}catch (InputMismatchException e) {e.printStackTrace();}finally {System.out.println("finally中的代码");if(sc!=null) {sc.close();}}return 0;}public static void main(String[] args) {int data = getData();System.out.println(data);}

getData()方法为了获取整数,没有获取到,抛出异常,return 0,获取到打印获取的整数,无论是否成功获取,都会执行finally中的代码,其中.close()为了释放资源。
另一种方式,可以不写close().
try后面实现了一个AutoCloseavable或Closeable接口的资源,Java运行时会在try块执行完毕后自动调用close方法

public static int getData() {try (Scanner sc = new Scanner(System.in)){int data = sc.nextInt();return data;}catch (InputMismatchException e) {e.printStackTrace();}finally {System.out.println("finally中的代码");}return 0;}

避免在finally中出现return语句

    public static int test() {try {return 10;}catch (NullPointerException e) {e.printStackTrace();}finally {return 20;}}public static void main(String[] args) {System.out.println(test());}

执行顺序:

  1. test执行,进入try。
  2. 执行return 10,但是try块中的return 语句实际返回值之前必须先执行finnaly。
  3. 执行finnaly,return 20,结束test方法,返回20
  4. 打印出20

throw和throws

  1. throw用于实际抛出的语句,throws表示该方法可能抛出的异常
  2. throw后面跟实例,throws后面跟异常类型
  3. throw可以用在任何方法体内,但是throws只能用在方法声明上

异常的处理流程

  1. 程序执行try中的代码
  2. 如果try中出现异常,结束执行try中的代码,catch进行捕获
  3. 如果捕获成功,执行catch中的代码,捕获失败向上传递给调用者,如果直到main方法没有合合适的代码处理异常,交给jvm,此时程序异常终止。
  4. 无论是否捕获成功,finally都会正常执行

自定义异常

在实际的开发中,Java中的异常不能完全表示遇到的一些异常,这是就需要自定义一些异常类来满足开发的需求。

我们根据空指针异常的源码对于自定义异常进行仿写

由此可得:

public class PassWordException extends Exception{public PassWordException() {}public PassWordException(String s) {super(s);}
}
public class userNameException extends Exception{public userNameException() {}public userNameException(String s) {super(s);}
}

那么总的实现是:
 

public class Login {private String userName;private String passWord;public void setUserName(String userName) {this.userName = userName;}public void setPassWord(String passWord) {this.passWord = passWord;}public void loginInfo(String userName, String passWord) throws userNameException, PassWordException {if(!this.userName.equals(userName)) {throw new userNameException("用户名错误!");}if(!this.passWord.equals(passWord)) {throw new PassWordException("密码错误!");}System.out.println("登录成功!");}
}
import java.util.Scanner;
class Test {public static void main(String[] args) {Login login = new Login();Scanner scanner = new Scanner(System.in);login.setUserName("abc");login.setPassWord("123");try {System.out.println("请输入用户名:");String userName = scanner.nextLine();System.out.println("请输入密码:");String passWord = scanner.nextLine();login.loginInfo(userName, passWord);}catch (userNameException e) {System.out.println("用户名错误!");e.printStackTrace();}catch (PassWordException e) {System.out.println("密码错误!");e.printStackTrace();}finally {scanner.close();}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Reality Capture 软件安装 附下载链接

Reality Capture 软件安装 文章目录 Reality Capture 软件安装一、Reality Capture v1.4汉化版安装包下载并解压二、Epic Games Launcher安装三、设置路径并安装![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f077210990674d9fa9c10b52338b52fe.png)四、启动Epic Ga…

第十四届中国国际健康产品展览会在沪举办,无限未来品牌大放异彩

2024 年,第十四届中国国际健康产品展览会、2024 亚洲天然及营养保健品展在上海成功举办。 此次展会聚焦天然及营养保健品领域,来自香港的 INFINITE FUTURE 无限未来品牌脱颖而出。无限未来将先进的营养科学与尖端数字技术融合,开发专业级营养…

Stylized Far East 古代国风建筑城镇宫殿场景模型

古代国风建筑城镇宫殿场景模型。内容: -演示场景(截图) - 种类繁多的建筑,如宫殿、商店、神社、房屋、餐馆、宝塔、寺庙等 -带有塔楼、门楼的模块化城堡墙 -树木、岩石、悬崖和其他自然资产 -传统装饰,如纸灯笼、绘画、瓷器等 - 城镇道具,如手推车、栅栏、板条箱、市场、…

【JavaEE】——TCP应答报文机制,超时重传机制

阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:TCP协议(面试重点重点) 1:报头长度 2:…

今年双十一可以买啥?2024双十一不用做功课闭眼入的品牌好物分享!

今年的双十一购物狂欢节即将来临,许多消费者已经开始规划他们的购物清单,期待在这个一年一度的促销盛会上抢购到心仪的商品。2024年的双十一,你无需再做繁琐的功课,因为这里将为你分享一些闭眼入的品牌好物,让你轻松享…

unity Gpu优化

不一样的视角,深度解读unity性能优化。unity性能优化,unity内存优化,cpu优化,gpu优化,资源优化,资源包、资源去重优化,ugui优化。 gpu优化静态批处理静态批处理原理规则静态合批的原理静态合批的…

【Sceneform-EQR】(手势优化)通过手势事件实现在AR/VR等三维场景中的控制模型旋转、平移与缩放

在上一篇文档中,我们实现了通过手势控制模型节点的旋转、缩放和平移。现在本文将介绍如何优化上一篇做的手势控制器,从而实现更好的跟手效果。 相关链接:【Sceneform-EQR】(手势控制器实现)通过手势事件实现在AR/VR等…

网络安全中的RCE命令执行漏洞----入门小白必看

RCE命令执行&代码执行漏洞 RCE命令执行漏洞 RCE漏洞简介 RCE(remote code/command execute) 远程代码/命令执行漏洞 RCE漏洞是两个漏洞: 代码执行漏洞 # 针对后端语言!命令执行漏洞 # 针对系统! 如何产生 在 Web应用中有时候程序员为了考虑灵活性、简洁性…

【SEO】什么是SEO?

什么是SEO(搜索引擎优化)?为什么SEO对于⼀个⽹站⾄关重要? SEO 全称是搜索引擎优化(Search Engine Optimization) 因为我们目前开发的网址,需要人看到,除了通过宣传营销的方式展现…

前端布局与响应式设计综合指南(二)

​🌈个人主页:前端青山 🔥系列专栏:Css篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Css篇专栏内容:前端布局与响应式设计综合指南(二) 目录 23、行内元素和块级元素?img算什么&…

影刀RPA实战:操作Mysql数据库

1.摘要 影刀RPA(Robotic Process Automation)是一种软件自动化工具,它可以模拟人类用户执行各种重复性任务,其中包括对数据库的操作。 我们可以使用软件自动化指令,通过获取数据库窗口对象来操作数据库,也…

《探秘数据合规官CCRC-DCO人员能力验证》

在当今竞争激烈的商业世界中,“数据合规官CCRC-DCO人员能力验证”这个词逐渐走入人们的视野。但究竟什么是数据合规官CCRC-DCO人员能力验证呢? 首先,咱们来明确一下概念。数据合规官CCRC-DCO人员能力验证,简单来说,就…

数仓范式建模和维度建模有什么不同?

在数据库设计的复杂世界中,还有一类建模方法,为范式建模,是一种旨在优化数据库结构、提高数据一致性和完整性的设计方法。本文将深入探讨范式建模的概念、原理、步骤以及与维度建模的区别。 一、什么是范式建模? 范式建模是一种…

Chromium 中window.DOMParser接口说明c++

一、DOMParser DOMParser 可以将存储在字符串中的 XML 或 HTML 源代码解析为一个 DOM Document。 备注: XMLHttpRequest 支持从 URL 可寻址资源解析 XML 和 HTML,在其response 属性中返回Document。 你可以使用XMLSerializer 接口执行相反的操作 - 将…

接口测试自动化后起之秀-YApi接口管理平台

前言 众多接口管理工具如雨后春笋,让人欣慰的是,有许多优秀作品来自国内,包含Yapi和rap,看着中文的官网,华丽的汉语,不禁让人大快朵颐,暗自称爽。当然这也就带来另一个弊端,使用基数…

nodejs的卸载和nvm安装

由于项目需求,需要多版本控制的nodejs,所以要把原来的nodejs卸载干净,然后再装nvm 常见问题 1.在安装nvm的时候没有卸载node,导致使用nvm安装完之后,node和npm都不可用。 2.在第一次使用nvm安装node后,要…

从零开始使用最新版Paddle【PaddleOCR系列】——第二部分:自建数据集 + 模型微调训练

目录 一、自建数据集 1.官方数据集格式参考 2.自建数据集txt文件编写代码 3.数据集检验 二、模型训练 1.模型配置yaml文件 2.命令行指令训练 在上一篇文章中,构建好了paddleOCR 运行必需的环境,并通过在线下载的方式,使用官方训练好的模型进…

深入理解 JDK 的 Optional 类

深入理解 JDK 的 Optional 类 深入理解 JDK 的 Optional 类1. 什么是 Optional?1.1 主要构造方法示例 2. Optional 的常用方法2.1 判断值是否存在示例2.2 获取值示例2.3 进行操作示例 3. 使用场景3.1 避免 null 值示例3.2 提高代码可读性3.3 与流结合示例 4. 注意事…

中航资本:股市融资50万一天的利息是多少?融资一般多久归还?

融资官方利率是8.35%,实际上大部分券商融资利息在6%~8%左右,详细利率因券商及投资者状况而异。少部分券商可提供低至5%,乃至更低的优惠利率。 该利息按天然日核算,融资利息融资金额融资年利率实际使用资金的天然日天数/360。 假…

基于深度学习的细粒度图像分析综述【翻译】

🥇 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 🎉 声明: 作为全网 AI 领域 干货最多的博主之一,❤️ 不负光阴不负卿 ❤️ 文章目录 基础信息0 摘要1 INTRODUCTION2 识别与检索 RECOGNITION VS. RETRIEVAL3 问题和…