Java基础教程 - 10 异常

更好的阅读体验:点这里 ( www.doubibiji.com

10 异常

10.1 异常的概念

什么是异常?

异常(Exceptions)是指在程序执行过程中出现的错误或异常情况,导致程序无法继续正常执行的事件。

但是程序语法错误和逻辑错误不属于异常。在 Java 中,异常分为 Error 和 Exception,但是 Error 是 Java 虚拟机无法解决的严重问题,例如递归调用没有跳出条件,导致无限递归产生的 StackOverflowError,或内存不足造成的 OutOfMemeryError,Error 异常一般不编写针对性的代码来处理,只能改代码来处理。我们在这里要针对性处理的是 Exception 异常。

Exception 又分为 编译时异常运行时异常

  • 编译时异常:在编译的时候就需要对可能存在的异常进行处理,也叫受检异常。
  • 运行时异常:在编译的时候不强制要求处理,也叫非受检异常,java.lang.RuntimeException 类及它的子类都是运行时异常。

异常类的继承关系及常见的异常类:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1 运行时异常举例

例如:整数除数是0会抛出异常。

public static void main(String[] args) {int i = 5 / 0;System.out.println(i);
}

执行的时候就会发生错误:

Exception in thread "main" java.lang.ArithmeticException: / by zeroat com.doubibiji.Test.main(Test.java:8)

当程序出现错误的时候,我们通常称之为抛出异常,抛出异常后,程序终止执行。

2 编译时异常举例

以 IO 异常为例:

public static void main(String[] args) {FileInputStream fis = new FileInputStream("xxx.txt");int x = fis.read();System.out.println(x);fis.close();
}

上面的代码无法通过编译,因为没有对编译时异常进行处理。

上面的 FileInputStream 是用来读取文件内容的,在后面的文件与IO章节会讲到。

10.2 捕获异常

程序抛出异常就无法继续执行了,但是任何程序都不可能是完美的没有bug的,只能尽可能的对错误进行预防和处理。

对异常进行预防和提前处理,这种行为通常称之为异常捕获。

一个程序出现任何错误,就停止运行肯定不是我们希望看到的,即使程序出现错误,哪怕给与用户一个错误提示,也是一种积极的处理方式。

1 异常捕获语法

最简单的异常捕获语法:

try {// 可能会抛出异常的代码
} catch (Exception e) {// 捕获并处理异常
}

举个栗子,捕获前面例子中运行时异常:

public static void main(String[] args) {try {int i = 5 / 0;System.out.println(i);} catch (Exception e) {// 捕获并处理异常System.out.println("除数不能为0");}System.out.println("异常后的代码");
}

将可能抛出异常的代码,放在 try 代码块中,上面的程序执行到 int i = 5 / 0; 会抛出异常,然后执行 catch 块中的语句。

出现异常后,在 try 代码块中,抛出异常语句之后的代码是无法被继续执行的,但是在 try-catch 后面的代码可以继续执行。

执行结果:

除数不能为0
异常后的代码

这样在发生错误的时候,可以给用户一个提示。当然具体的处理方式需要根据业务需求的处理,这里只是举个例子。

另外如果方法有返回值,还需要在 catch 块中,根据需要进行返回:

public static int test() {try {int[] nums = new int[]{1, 2, 3};return nums[3];         // 会抛出异常} catch (Exception e) {e.printStackTrace();return 0;		// 需要返回值,否则方法没有返回值}
}

2 打印异常详细信息

捕获异常后,在 catch 块中,可以通过异常对象和 stacktrace 对象打印异常的详细信息。

public static void main(String[] args) {try {int i = 5 / 0;System.out.println(i);} catch (Exception e) {// 捕获并处理异常System.out.println("除数不能为0");System.out.println(e.getMessage()); // 打印异常信息:/ by zeroe.printStackTrace();    // 打印异常堆栈跟踪信息}System.out.println("异常后的代码");
}

执行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3 捕获指定类型的异常

在程序运行时,可能会出现不同类型的异常,有时候可能只想捕获和处理指定类型的异常,这个时候就需要根据类型来捕获异常了。因为 Exception e 会捕获所有类型的异常。

语法:

public static void main(String[] args) {try {int i = 5 / 0;System.out.println(i);} catch (ArithmeticException e) {// 捕获并处理异常System.out.println("除数不能为0");e.printStackTrace();}System.out.println("异常后的代码");
}

上面捕获了 ArithmeticException 类型的异常,在捕获异常后,打印了异常信息和提示信息。

需要注意,上面只是捕获了 ArithmeticException 类型的异常,如果有代码抛出了其他类型的异常,是无法捕获的。


举个栗子,我们修改代码如下:

public static void main(String[] args) {try {int[] nums = new int[3];System.out.println(nums[3]);} catch (ArithmeticException e) {// 捕获并处理异常System.out.println("除数不能为0");e.printStackTrace();}System.out.println("异常后的代码");
}

在上面的代码中,nums 的长度为 3,所以 nums[3] 会报数组越界异常(ArrayIndexOutOfBoundsException) ,但是我们没有捕获这个异常,导致程序终止。

执行信息:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3at com.doubibiji.Test.main(Test.java:11)

如果想单独针对某个异常做特殊处理,并其他异常使用 Exception 进行兜底,这种情况需要捕获多个异常。

4 捕获多个异常

我们可以同时捕获多个异常,并对每种异常可以采用不同的处理。

举个栗子:

public static void main(String[] args) {try {int[] nums = new int[3];System.out.println(nums[3]);} catch (ArithmeticException e) {// 捕获并处理异常System.out.println("除数不能为0");e.printStackTrace();} catch (ArrayIndexOutOfBoundsException e) {// 捕获并处理异常System.out.println("数组越界");e.printStackTrace();} catch (Exception e) {e.printStackTrace();}System.out.println("异常后的代码");
}

如果我们不能判断是否还会抛出其他类型的错误,可以在最后添加 catch (Exception e) 用来捕获其他类型的错误。

5 对多个异常使用相同的处理

刚才针对指定的异常进行捕获,然后针对性的处理。

如果相对多个异常采用相同的处理,那么可以使用 | 操作符。

举个例子:

try {int[] nums = new int[3];System.out.println(nums[3]);
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {	// 统一处理两个类型的异常// 捕获并处理异常System.out.println("统一处理多个异常");e.printStackTrace();
} catch (Exception e) {e.printStackTrace();
}

6 异常finally

finally 表示的是无论是否发生异常都要执行的代码。

举个栗子:

public static void main(String[] args) {try {int[] nums = new int[3];System.out.println(nums[3]);} catch (Exception e) {System.out.println("出现异常");return ;} finally {System.out.println("出现异常也会被执行");}System.out.println("异常后的代码");
}

执行结果:

出现异常
出现异常也会被执行

哪怕出现异常,使用 return 返回,终止了方法的执行,但是 finally 代码块还是在返回之前被执行。

finally 一般在文件读写操作的时候用的比较多,就是不管是否发生错误都要关闭文件,所以可以将文件的关闭操作放在 finally 块中。

举个例子,捕获前面例子中的编译时异常:

public static void main(String[] args) {FileInputStream fis = null;try {fis = new FileInputStream("xxx.txt");int x = fis.read();System.out.println(x);} catch (IOException e) {e.printStackTrace();} finally {try {fis.close();    // 关闭也会抛出异常} catch(IOException e) {e.printStackTrace();}}
}

在上面的代码中,对文件进行读取,最终在 finally 块中关闭流,关于 IO 后面的章节再讲,这里可以看出,try-catch-finally 是可以嵌套的。


再看一段代码:
public class ExceptionTest {public static void main(String[] args) {int i = test();System.out.println(i);  // 3}public static int test() {try {int[] nums = new int[]{1, 2, 3};return nums[3];         // 抛出异常} catch (Exception e) {e.printStackTrace();return 2;} finally {System.out.println("一定会执行");return 3;}}
}

在 test() 方法中,try 代码块中会抛出异常,进入到 catch 代码块中,但是在 return 2 之前会执行 finally 代码块中的内容,所以会先执行 return 3,但是 return 后方法就结束了,所以返回值是 3

10.3 throws异常

前面使用 try-catch-finally 捕获异常并进行处理,这是一种异常的处理方式。

另一种异常的处理方式就是使用 throws 进行处理,其实这种处理方式就是不处理,而是将异常往上抛,抛给调用的方法,并没有真正处理异常。

例如之前的编译时异常,我们使用了 try-catch-finally 进行捕获处理,也可以使用 throws 抛出异常。

public class ExceptionTest {public static void main(String[] args) {try {test();} catch(IOException e) {e.printStackTrace();}}// 将IOException抛出,交由调用者处理public static void test() throws IOException {FileInputStream fis = new FileInputStream("xxx.txt");int x = fis.read();System.out.println(x);fis.close();}
}

在上面的代码中,test() 中的代码是会抛出编译时异常的,但是没有使用 try-catch-finally 进行捕获处理,而是直接使用 throws 指明此方法会抛出的异常,那么此方法就不用对异进行处理了,而是由调用者进行处理,调用者可以使用 try-catch-finally 进行捕获处理,或者也可以使用 throws 进行处理,继续向上抛出。

在子类重写父类方法的时候,父类方法使用throws指明了抛出的异常类型,那么子类方法throws的异常类型不能大于父类抛出的异常类型,只能是父类抛出异常的类型或其子类型。如果父类方法没有throws异常,重写的时候也不能throws异常。

10.4 异常的传递

什么是异常的传递?

异常的传递,就是当方法执行的时候出现异常,如果没有进行捕获,就会将异常传递给该方法的调用者,如果调用者仍未处理异常,则继续向上传递,直到传递给主程序,如果主程序仍然没有进行异常处理,则程序将被终止。

举个栗子:

public class Test{public static void main(String[] args) {try {testException();} catch (Exception e) {e.printStackTrace();}}public static void testException() {testNullPoint();}public static void testNullPoint() {String str = null;str.length();   // 会抛出空指针异常}
}

上面代码,执行 testNullPoint() 会抛出空指针异常,因为 testNullPoint() 函数中没有进行异常处理,则异常会抛给 testException() 函数,testException() 没有进行异常处理,则抛给 main() 函数,main() 函数中则对异常进行了处理,程序不会崩溃。

利用异常的传递性,如果我们在 main() 函数中进行了异常捕获,无论程序哪里发生了错误,最终都会被传递到 main() 函数中,保证所有的异常都会被捕获。但是不要所有的异常都在 main()函数中处理,main() 函数中的异常处理只是兜底处理。

10.5 主动抛出异常

除了代码执行的时候出错,系统会主动抛出异常,我们还可以根据实际的业务需要,主动抛出异常。

首先创建一个异常对象,然后使用 throw 关键字抛出异常对象(不是 throws)。

举个栗子:

public class Test{public static void main(String[] args) {try {String name = inputUsername();System.out.println("输入的用户名:" + name);} catch (Exception e) {System.out.println("用户名格式错误,请重新输入");}}/*** 从键盘读取用户名*/public static String inputUsername() {System.out.println("请输入用户名:");Scanner scanner = new Scanner(System.in);// 读取键盘输入String name = scanner.nextLine();if (null == name || name.length() > 16 || name.length() < 8) {throw new RuntimeException("用户名格式错误"); // 主动抛出异常}return name;}
}

在上面的代码中,如果输入用户名不正确,主动创建一个 RuntimeException 异常对象,并使用 throw 抛出。

当输入abc的时候,执行结果:

请输入用户名:
abc
用户名格式错误,请重新输入

10.6 自定义异常类

除了使用 Java 内置的异常类型外,您还可以自定义异常类,以便更好地描述特定的异常情况。

自定义异常类一般情况下都是继承 Exception 或 RuntimeException 类,如果继承 Exception,属于编译时异常,需要在编译的时候就要处理,如果继承 RuntimeException,那么是运行时异常。

异常类建议以 Exception 结尾,见名知意。

举个栗子:

下面我们首先自定义了两个异常类,然后根据需要抛出这两个异常类的对象,在捕获异常的时候,根据异常类型进行不同的处理。

并在自定义异常类中可以封装自定义的参数。

import java.util.Scanner;// 定义异常类一:一般自定义异常类,定义两个构造方法,并调用父类的构造方法
class UsernameEmptyException extends RuntimeException {public UsernameEmptyException() {}public UsernameEmptyException(String message) {super(message);}
}// 定义异常类二:可以在自己的异常类中定义各种参数
class UsernameLengthException extends RuntimeException {int minLength;int maxLength;String message;// 自定义异常类public UsernameLengthException(String message, int minLength, int maxLength) {super(message);		// 调用父类构造,并传递异常信息this.message = message;this.minLength = minLength;this.maxLength = maxLength;}@Overridepublic String toString() {return this.message + ", minLength:" + this.minLength + ", maxLength:" + this.maxLength;}
}/*** 测试类*/
public class ExceptionTest {public static void main(String[] args) {try {String username = inputUsername();System.out.println("输入的用户名:$password");} catch(UsernameEmptyException e) {System.out.println("用户名不能为空");} catch (UsernameLengthException e) {System.out.println(e.getMessage());}}public static String inputUsername() {System.out.println("请输入用户名:");Scanner scanner = new Scanner(System.in);// 读取键盘输入String name = scanner.nextLine();if (null == name || name.length() < 1) {throw new UsernameEmptyException("用户名为空"); // 抛出异常}if (name.length() > 16 || name.length() < 8) {throw new UsernameLengthException("用户名格式错误", 8, 16); // 抛出异常}return name;}
}

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

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

相关文章

R_AARCH64_ADR_PREL_PG_HI21问题说明

目录 问题现象&#xff1a; 问题原因 问题机理 问题现象&#xff1a; 客户现场加载out文件出现如下问题&#xff1a; 打印“Relocation of type ‘R_AARCH64_ADR_PREL_PG_HI22…..’”,明确是ARDP指令引起的问题 问题原因 ARDP的寻址范围是4GB范围&#xff0c;加载的位置…

Linux C语言学习:数据类型

一、 为什么要引入数据类型 • 计算机中每个字节都有一个地址&#xff08;类似门牌号&#xff09; • CPU通过 地址 来访问这个字节的空间 0x20001103 1 0 0 1 0 0 1 1 0x20001102 1 1 1 0 1 1 1 0 0x20001101 1 1 1 1 0 1 0 1 0x20001100 0 …

密码学基本概念(补充)

BiBa模型的*特性规则&#xff1a;主体不能修改更高完整级的客体&#xff08;主题不能向上写&#xff09; Diffie-Hellman密钥交换协议的安全性基于求解离散对数的困难性&#xff0c;既对于C^d M mod P&#xff0c;在已知C和P的前提下&#xff0c;由d求M很容易&#xff0c;但是…

Transformer系列:图文详解KV-Cache,解码器推理加速优化

前言 KV-Cache是一种加速Transformer推理的策略&#xff0c;几乎所有自回归模型都内置了KV-Cache&#xff0c;理解KV-Cache有助于更深刻地认识Transformer中注意力机制的工作方式。 自回归推理过程知识准备 自回归模型采用shift-right的训练方式&#xff0c;用前文预测下一个…

EditPlus 输入错误: 没有文件扩展“.js”的脚本引擎

原因 JS扩展名的文件被其他软件关联了&#xff0c;需要取消关联 解决办法 cmd窗口&#xff0c;输入 regedit 进入注册表&#xff0c; 打开注册表编辑器&#xff0c;定位[HKEY_CLASSES_ROOT\.js]这一项&#xff0c;双击默认值将其改为“JSFile”即可

Codeforces Round 948 (Div. 2) A~D

A. Little Nikita &#xff08;思维&#xff09; 题意&#xff1a; 小 A A A决定用一些立方体建一座塔。一开始&#xff0c;塔上没有任何立方体。在一次移动中&#xff0c;小 A A A要么正好把 1 1 1 个立方体放到塔顶&#xff0c;要么正好从塔顶移走 1 1 1 个立方体。存不存…

信息可溯、安全可控 | SW-LIMS 采测分离监测模式解析

数据的准确性在环境监测过程中至关重要,为了确保环监数据的真实有效,并满足“全程留痕、全程监控、信息可溯、安全可控”的要求,采测分离监测模式是一个有效的解决方案。 这种模式通过将样品采集和样品检测交由不同的单位完成,形成了相互独立、相互监督的工作机制,有助于减少潜…

LeetCode刷题之HOT100之跳跃游戏

2024/6/5 今天下起了绵密细雨&#xff0c;空气清新很多。昨晚做的梦较魔幻&#xff0c;可能也是导致我睡觉时业已破损的小米手环8的表腕断裂的因素之一。来到实验室&#xff0c;打扫一下卫生&#xff0c;听听歌&#xff0c;做道题。好不自在呀&#xff01; 1、题目描述 2、逻辑…

mysql中optimizer trace的作用

大家好。对于MySQL 5.6以及之前的版本来说&#xff0c;查询优化器就像是一个黑盒子一样&#xff0c;我们只能通过EXPLAIN语句查看到最后 优化器决定使用的执行计划&#xff0c;却无法知道它为什么做这个决策。于是在MySQL5.6以及之后的版本中&#xff0c;MySQL新增了一个optimi…

我国液碱产量逐渐增长 行业集中度有望不断提升

我国液碱产量逐渐增长 行业集中度有望不断提升 液碱是由氢氧化钠&#xff08;NaOH&#xff09;、氢氧化钾&#xff08;KOH&#xff09;等化合物以及水组成的一种碱性化合物。液碱的相对分子质量为40.00&#xff0c;密度为1.318g/cm&#xff0c;在常温常压下多表现为一种无色、无…

12 - 常用类

那就别跟他们比&#xff0c;先跟自己比&#xff0c;争取今天比昨天强一些&#xff0c;明天比今天强一些。 1.包装类 针对八种基本数据类型封装的相应的引用类型。 有了类的特点&#xff0c;就可以调用类中的方法。&#xff08;为什么要封装&#xff09; 基本数据类型包装类b…

JavaSE——学习总结

一、初识Java 运行Java程序 Java是一门半编译型、半解释型语言 先通过javac编译程序把源文件进行编译&#xff0c;编译后生成的.class文件是由字节码组成的&#xff0c;和平台无关、面向JVM的文件&#xff0c;最后启动java虚拟机来运行.class文件&#xff0c;此时JVM会将字节…

目标检测数据集 - 城市道路行驶车辆检测数据集下载「包含VOC、COCO、YOLO三种格式」

​​​数据集介绍&#xff1a;城市道路行驶车辆检测数据集&#xff0c;真实监控场景高质量图片数据&#xff0c;涉及场景丰富&#xff0c;比如城市道路快速行驶车辆、城市道路慢速行驶车辆、城市道路密集行驶车辆、城市道路夜间低光行驶车辆数据等。数据集标注标签划分为 "…

python-字符替换

[题目描述] 给出一个字符串 s 和 q 次操作&#xff0c;每次操作将 s 中的某一个字符a全部替换成字符b&#xff0c;输出 q 次操作后的字符串输入 输入共 q2 行 第一行一个字符串 s 第二行一个正整数 q&#xff0c;表示操作次数 之后 q 行每行“a b”表示把 s 中所有的a替换成b输…

使用kubespray部署k8s生产环境

使用kubespray部署k8s生产环境 系统环境 OS: Static hostname: test Icon name: computer-vm Chassis: vm Machine ID: 22349ac6f9ba406293d0541bcba7c05d Boot ID: 83bb7e5dbf27453c94ff9f1fe88d5f02 Virtualization: vmware Operating System: Ubuntu 22.04.4 LTS Kernel: L…

mac M1下安装PySide2

在M1下装不了PySide2, 是因为PySide2没有arm架构的包 1 先在M1上装qt5 安装qt主要是为了能用里面的Desinger, uic, rcc brew install qt5 我装完的路径在/opt/homebrew/opt/qt5 其中Designer就是用来设计界面的 rcc用resource compiler, 编绎rc资源文件的, 生成对应的py文件…

echarts legend. icon的展示

默认展示 icon展示circle圆形rect矩形roundRect圆角矩形triangle三角形diamond菱形pin水滴arrow箭头none不显示

Redis位图

简介 在我们平时开发过程中&#xff0c;会有一些bool型数据需要存取&#xff0c;比如用户一年的签到记录&#xff0c;签了是1&#xff0c;没签是0&#xff0c;要记录365天。如果使用普通的key/value&#xff0c;每个用户要记录365个&#xff0c;当用户上亿的时候&#xff0c;需…

数据中心综合解决方案

安科瑞电气股份有限公司 祁洁 acrelqj 一、方案介绍 安科瑞电气紧跟数据中心发展形式&#xff0c;推出数据中心综合解决方案&#xff0c;集成了变配电监测、电源备自投、电气接点测温、智能照明控制、电能质量监测及治理、蓄电池在线监测、精密配电监控、智能母线监控以及消…

重要经济数据对行情的影响有多大?

金融市场上的消息非常多&#xff0c;可以来自不同国家、不同大型企业&#xff0c;也可以由不同机构统计公布&#xff0c;甚至是各国政府或中央银行的发表。在宏观经济层面上&#xff0c;所有政经消息都属于金融市场的风险事件&#xff0c;大多能引起市场波动&#xff0c;因此投…