认识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.mzph.cn/web/55235.shtml

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

相关文章

FreeRTOS应用开发学习

了解FreeRTOS 任务相关API FreeRTOS任务创建API FreeRTOS 中,任务的创建有两种方法,一种是使用动态创建,一种是使用静态创建。动态创建时,任务控制块和栈的内存是创建任务时动态分配的,任务删除时,内存可…

微信开发者工具提示获取手机号失败,客户端短信认证

长时间没有使用快捷登录方式,手机号授权过期, 如何解决 打开 开发者工具中,预览模式,在手机中完成,使用快捷登录,获取完整的手机号流程;验短流程完成后在开发工具也能获取到完整手机号了 Tar…

Mac电脑使用pyenv管理多版本python环境 _

利用Mac包管理工具brew安装pyenv,pyenv用来管理所有python版本。如果没有安装brew,先安装一下吧。 安装pyevn $ brew install pyenv $ pyenv -v pyenv 1.2.6查看所有的python版本(pyenv管理的所有版本) $ pyenv versions * sys…

TOML 格式配置文件:简洁与强大的选择

在软件开发中,配置文件是不可或缺的一部分。它们用于存储应用程序的设置、参数和其他重要信息。不同的配置文件格式各有特点,本文将介绍 TOML 格式配置文件,并与 YAML 格式进行对比,探讨其优劣。 一、TOML 格式介绍 TOML&#x…

LSTM和GRU

LSTM(Long Short-Term Memory)和GRU(Gated Recurrent Unit)都是循环神经网络(Recurrent Neural Networks,RNNs)的变体,专门设计用来解决传统RNN在处理长序列数据时遇到的梯度消失或梯…

C#里使用PerformLayout,强制控件将布局逻辑应用于其所有子控件。

前几天,使用DataGridView来进行动态数据显示,但是发现左边的滚动条会显示不正确。 比如设置显示第100行了,但是滚动条的位置还是在最顶端, 如果你去点击一下滚动条,它又立即更新,并且跳到正确的位置显示。 …

申请商家转账到零钱功能所需材料及必过攻略

商家转账到零钱功能的快速开通方法,可以归纳为以下几个步骤: 一、确认商户资格与账号状态 1. 商户类型:该功能通常只对公司性质的商户开放,个体工商户及小微商户暂时无法申请。商家需为微信支付认证用户。 2. 账号状态&#xff…

网络层及ip报头

★★★★★默写: A类:0~127 B类:128~191 C类:192~223 A类私网:10.0.0 - 10.255.255.255 B类私网:172.16.0.0 - 172.31.255.255 C类私网:19.168.0.0 - 192.168.255.255 特殊: 0.0.0…

Windows远程桌面到Ubuntu

在Ubuntu系统中,默认情况下root账户是被禁用的,为了安全起见,建议不要直接使用root账户登录图形界面。但是,如果出于特定的管理或维护需求,您可以按照以下步骤启用和使用root账户登录图形界面: 启用root账户…

新手爬虫DAY1

这个错误信息表明在你的Python程序中,re.search() 函数没有找到预期的匹配项,因此返回了 None。当你尝试在 None 对象上调用 group(1) 方法时,Python 抛出了一个 AttributeError。 具体来说,错误发生在 pc.py 文件的第6行&#x…

AI大模型与相对论的结合点的思考、应用及相对论原理与公式表达

大家好,我是微学AI,今天给大家介绍一下AI大模型与相对论的结合点的思考、应用及相对论原理与公式表达。在阐述相对论原理的基础上,通过数学复杂公式,分析了人工智能大模型在相对论领域的应用前景。文章深入挖掘了两大领域之间的联…

浏览器哪个好,占用cpu低。。电脑卡。流氓软件。。。火狐浏览器的使用。

用360安全浏览器打开b站,有时候占用CPU会升高,高达90%以上。一关闭b站就回落。 用谷歌浏览器打开b站,有时候占用CPU会升高,高达60%、70%,比360安全浏览器低一些。。一关闭b站就回落。 360安全浏览器、QQ浏览器&#xf…

厨房老鼠数据集:掀起餐饮卫生监测的科技浪潮

厨房老鼠数据集:掀起餐饮卫生监测的科技浪潮 摘要:本文深入探讨了厨房老鼠数据集在餐饮行业卫生管理中的重要性及其相关技术应用。厨房老鼠数据集通过收集夜间厨房图像、老鼠标注信息以及环境数据,为深度学习模型提供了丰富的训练样本。基于…

MongoDB 安装配置及配置和启动服务

MongoDB 安装配置 附:MongoDB官网下载地址: https://www.mongodb.com/download-center/community 注: 官网可以下载最新版的MongoDB安装包,有MSI安装版和ZIP安装版。我们课堂上使用4.4.4的ZIP安装版。安装版参考博客&#xff1…

Spark第一天

MapReduce过程复习 Spark由五部分组成 RDD五大特征 1、 Spark -- 代替MapReduce <<<<< scala是单机的&#xff0c;spark是分布式的。>>>>> 开源的分布式计算引擎 可以快速做计算 -- 因为可以利用内存来做一些计算 (1) 分为5个库(模块) : 1、…

安装指定node.js 版本 精简版流程

首先 我们本机上是否安装有node 如果有 需要先卸载 卸载完成后 使用命令查看是否卸载干净 打开WinR 输入cmd 然后输入如下名: where node 如果没有目录显示 说明node 很干净 本机没有相关安装 在输入命令: where npm 如果有相关目录 需要删除掉 要不然 后续安装的…

报错 - LangChain bind_tools NotImplementedError

使用 LangChain 的 bind_tools 方法一直报错&#xff0c;即使使用 ChatOpenAI 作为 llm 接口 根据这个issue 下的回答&#xff0c;修改了 ChatOpenAI 的 import 出处&#xff0c;解决了问题 https://github.com/langchain-ai/langchain/issues/21479#issuecomment-2105618237 …

基于华为昇腾910B,实战 InternLM2.5-7B-Chat 模型推理

本文将带领大家基于启智平台&#xff0c;使用 LMDeploy 推理框架在华为昇腾 910B 上实现 internlm2_5-7b-chat 模型的推理。 GitHub - InternLM/lmdeploy: LMDeploy is a toolkit for compressing, deploying, and serving LLMs.&#xff08;欢迎star&#xff09; GitHub - I…

Opencv库的安装与vs项目配置

目录 一、下载安装opencv 1、下载 2、减压安装 3、环境变量配置&#xff08;vs项目不是必须的&#xff0c;看后面&#xff09; 二、vs项目配置opencv 1、创建vs项目 2、包含opencv头文件 一、下载安装opencv 1、下载 OpenCV - Open Computer Vision Library 2、减压安…

k8s杂记

在node节点内部使用kubectl&#xff1a; rootmultinode-demo-m02:/# ps aux | grep kubelet root 218 3.1 1.6 2066316 62516 ? Ssl 07:35 0:29 /var/lib/minikube/binaries/v1.30.0/kubelet --bootstrap-kubeconfig/etc/kubernetes/bootstrap-kubelet.con…