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

零基础学Java第二十二讲---异常(2)

        续接上一讲

目录

一、异常的处理(续)

1、异常的捕获-try-catch捕获并处理异常

1.1关于异常的处理方式

2、finally

3、异常的处理流程

二、自定义异常类

1、实现自定义异常类


一、异常的处理(续)

1、异常的捕获-try-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.1关于异常的处理方式

异常的种类有很多,我们要根据不同的业务场景来决定:

(1)对于比较严重的问题(如算钱),应该直接让程序崩溃,减小损失

(2)对于不太严重的问题,可以记录错误日志,通过监控报警程序及时通知告知程序猿

(3)对于可能会恢复的问题(网络相关场景),可以尝试重试

        在我们当前的代码中采取的是经过简化的第⼆种方式.我们记录的错误日志是出现异常的方法调用信息,能很快速的让我们找到出现异常的位置.以后在实际工作中我们会采取更完备的方式来记录异常信息

#注:

(1)try块内抛出异常位置之后的代码将不会被执行

(2)如果抛出异常类型与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: 3at day20210917.ArrayOperator.main(ArrayOperator.java:24)

(3)try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获

 public static void main(String[] args) {int[] array = {1, 2, 3};try {System.out.println("before");// array  = null;System.out.println(array [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

(4)可以通过⼀个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进行类型匹配的时候,不光会匹配相同类型的异常对象,也会捕捉目标异常类型的子类对 象

2、finally

        在写程序时,有些特定的代码,不论程序是否发⽣异常,都需要执行,比如程序中打开的资源:网络连接、数据库连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。

语法格式:
try{// 可能会发⽣异常的代码 
}catch(异常类型 e){// 对捕获到的异常进⾏处理 
}finally{// 此处的语句⽆论是否发⽣异常,都会被执⾏到
}// 如果没有抛出异常,或者异常被捕获处理了,这⾥的代码也会执⾏
public static void main(String[] args) {try{int[] array = {1,2,3};array [100] = 10;array [0] = 10;}catch (ArrayIndexOutOfBoundsException e){System.out.println(e);}finally {System.out.println("finally中的代码⼀定会执⾏");}System.out.println("如果没有抛出异常,或者异常被处理了,try-catch后的代码也会执⾏");}

#注:finally中的代码⼀定会执行的,⼀般在finally中进行⼀些资源清理的扫尾工作,如果异常被捕获,那么将不会继续执行后续的内容,而是直接走完当前捕获异常的catch后直接走finally(除了finally其他的都不执行)

        finally 执行的时机是在方法返回之前(try或者catch中如果有return会在这个return之前执行 finally). 但是如果finally 中也存在return语句,那么就会执行finally中的return,从而不会执行到try 中原有的return.

        ⼀般我们不建议在finally中写return(会被编译器当做⼀个警告)

3、异常的处理流程

关于“调用栈”:

        方法之间是存在相互调用关系的,这种调用关系我们可以"调用栈"来描述.在JVM中有⼀块内存空间称为"虚拟机栈",专门存储方法之间的调用关系.当代码中出现异常的时候,我们就可以使用 e.printStackTrace(); 的方式查看出现异常代码的调用栈.

        如果本方法中没有合适的处理异常的方式,就会沿着调用栈向上传递

 public static void main(String[] args) {try {func();} catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();}System.out.println("after try catch");}public static void func() {int[] array = {1, 2, 3};System.out.println(array[100]);}//结果java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 3at LibrarySystem.func(LibrarySystem.java:107)at LibrarySystem.main(LibrarySystem.java:98)after try catch

        如果向上⼀直传递都没有合适的方法处理异常,最终就会交给JVM处理,程序就会异常终止(和我们最开始未使用trycatch时是⼀样的)

异常处理流程总结:

(1)程序先执行try中的代码

(2)如果try中的代码出现异常,就会结束try中的代码,看和catch中的异常类型是否匹配

(3)如果找到匹配的异常类型,就会执行catch中的代码

(4)如果没有找到匹配的异常类型,就会将异常向上传递到上层调用者

(5)无论是否找到匹配的异常类型,finally中的代码都会被执行到(在该方法结束之前执行)

(6)如果上层调用者也没有处理的了异常,就继续向上传递

(7)⼀直到main方法也没有合适的代码处理异常,就会交给JVM来进行处理,此时程序就会异常终止

二、自定义异常类

        Java 中虽然已经内置了丰富的异常类,但是并不能完全表示实际开发中所遇到的⼀些异常,此时就需要维护符合我们实际情况的异常结构

例如,我们实现⼀个用户登陆功能:

 public class LogIn {private String userName = "admin";private String password = "123456";public void loginInfo(String userName, String password) {if (!this.userName.equals(userName)) {System.out.println("⽤⼾名错误!");return;}if (!this.password.equals(password)) {System.out.println("密码错误!");return;}System.out.println("登陆成功");}public static void main(String[] args) {LogIn logIn = new LogIn();logIn.loginInfo("admin111", "123456");}}

        此时我们在处理用户名密码错误的时候可能就需要抛出两种异常.我们可以基于已有的异常类进行扩展 (继承),创建和我们业务相关的异常类

1、实现自定义异常类

具体方式:

(1)自定义异常类,然后继承自Exception或者RunTimeException

(2)实现⼀个带有String类型参数的构造方法,参数含义:出现异常的原因

 class UserNameException extends Exception {public UserNameException(String message) {super(message);}}class PasswordException extends Exception {public PasswordException(String message) {super(message);}}

此时我们的LogIn代码可以改成:

public class LogIn {private String userName = "admin";private String password = "123456";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("登陆成功");}public static void main(String[] args) {try {LogIn login = new LogIn();login.loginInfo("admin", "123456");} catch (UserNameException e) {e.printStackTrace();} catch (PasswordException e) {e.printStackTrace();}}}

#注:

(1)自定义异常通常会继承自Exception或者RuntimeException

(2)继承自Exception的异常默认是受查异常

(3)继承自RuntimeException的异常默认是非受查异常

http://www.lryc.cn/news/626333.html

相关文章:

  • KV cache
  • 在Excel和WPS表格中制作可打印的九九乘法表
  • MySQL事务及原理详解
  • MySQL 数据与表结构导出 Excel 技术文档
  • 如何使用matlab将目录下不同的excel表合并成一个表
  • python中view把矩阵维度降低的时候是什么一个排序顺序
  • 系统架构设计师备考第1天——系统架构概述
  • 深入Linux内核:架构设计与核心功能解析
  • 车联网(V2X)中万物的重新定义---联网汽车新时代
  • 自动驾驶汽车机器学习安全实用解决方案
  • RK android14 Setting一级菜单IR遥控器无法聚焦问题解决方法
  • Building Systems with the ChatGPT API 使用 ChatGPT API 搭建系统(第二章学习笔记及总结)
  • 汽车ECU实现数据安全存储(机密性保护)的一种方案
  • 【openssl】openssl CA.pl 签发证书操作步骤
  • Redis String全方位指南:命令、编码、时间复杂度与应用场景
  • RK-Android11-PackageInstaller安装器自动安装功能实现
  • KubeBlocks AI:AI时代的云原生数据库运维探索
  • 3D文档控件Aspose.3D实用教程:使用 C# 构建 OBJ 到 U3D 转换器
  • Origin将普通点线图升级为3D点线图
  • ETL 工具选型评测:2025 年 Top 5 工具优缺点对比(附评分表)
  • 【自记】Power BI 中FILTER、CALCULATE 和 CALCULATETABLE 三个函数详细说明
  • React框架超详细入门到实战项目演练【前端】【React】
  • React15.x版本 子组件调用父组件的方法,从props中拿的,这个方法里面有个setState,结果调用报错
  • 【Coze】Windows 环境下使用 Docker 部署 Coze Studio 的详细指南
  • 基于分布式环境的令牌桶与漏桶限流算法对比与实践指南
  • Day 40:训练和测试的规范写法
  • 008.Redis Cluster集群架构实践
  • RabbitMQ:SpringAMQP Topic Exchange(主题交换机)
  • Linux中Cobbler服务部署与配置(快速部署和管理 Linux 系统)
  • mac电脑软件左上角的关闭/最小化/最大化按钮菜单的宽度和高度是多少像素