Java基础二十一(异常捕获和处理)

1. 异常


1.1 概述

(1) 认识异常

异常是指程序在运行过程中出现非正常情况。

(2) Java 异常体系结构

在这里插入图片描述
所有异常类都是 Throwable 类的子类,它派生出两个子类,Error 类和 Exception 类。
(1)Error 类 : 表示程序无法恢复的严重错误或者恢复起来比较麻烦的错误,例如内存溢出、动态链接失败、虚拟机错误等。应用程序不应该主动抛出这种类型的错误,通常由虚拟机自动抛出。如果出现这种错误,最好的处理方式是让程序安全退出。
(2)Exception 类 : 由Java应用程序抛出和处理的非严重错误,例如文件未找到、网络连接问题、算术错误(如除以零)、数组越界、加载不存在的类、对空对象进行操作、类型转换异常等。Exception类的不同子类对应不同类型的异常。。Exception类又可分为两大类异常:

  • 不受检异常:也称为 unchecked 异常,包括 RuntimeException 及其所有子类和 Error。对这类异常并不要求强制进行处理,例如算术异常ArithmeticException等。
  • 受检异常:也称为 checked 异常,指除了不受检异常外,其他继承自 Exception 类的异常。对这类异常要求在代码中进行显式处理。

程序中常见异常

异常类名分类说明
Exception设计时异常异常层次结构的根类
IOException设计时异常IO异常的根类,属于非运行时异常
FileNotFoundException设计时异常文件操作时,找不到文件,属于非运行时异常
RuntimeException运行时异常运行时异常的根类,RuntimeException及其子类不要求处理
ArithmeticException运行时异常算术运算异常,例如除数为零,属于运行时异常
IllegalArgumentException运行时异常方法接收到非法参数,属于运行时异常
ArrayIndexOutOfBoundsException运行时异常数组越界访问异常,属于运行时异常
NullPointerException运行时异常尝试访问null对象的成员时发生的空指针异常,属于运行时异常
ArrayStoreException运行时异常数据存储异常,写数组操作时,对象或数据类型不兼容
ClassCastException运行时异常类型转换异常
IllegalThreadStateException运行时异常试图非法改变线程状态,例如试图启动一已经运行的线程
NumberFormatException运行时异常数据格式异常,试图把字符串非法转换成数值

上述异常类按照设计时异常和运行时异常进行了分类,并提供了相应的说明。设计时异常通常属于编译时异常,需要在代码中进行处理或声明抛出;而运行时异常通常不要求强制处理,可以选择捕获和处理,也可以由调用者处理,如果没有处理,将会导致程序异常终止。

1.2 Java异常处理机制

1.2.1 异常处理

(1)用 trycatchfinally 来捕获和处理异常

  • try 块中包含可能会抛出异常的代码
  • catch 块用于捕获并处理指定类型的异常
  • finally 块中的代码无论是否发生异常都会被执行,通常用于释放资源或清理操作

(2)用 throwthrows 来抛出异常

  • throw 关键字用于手动抛出异常
public void method() throws CustomException {if (condition) {throw new CustomException("This is a custom exception");}
}
  • throws 关键字用于在方法中声明指定可以抛出的异常类型,表示该方法可能会抛出该类的异常,由调用者来处理
public void method() throws IOException, CustomException {// 方法体
}

throw 用于具体的异常对象,而 throws 用于异常类型的声明。

1.2.2 捕获异常

(1)try-catch 处理异常

public class ExceptionTryCatch {public static void main(String[] args) {try {int i = 1,j = 0,res;System.out.println("begin");res = i / j;System.out.println("end");} catch (Exception e) {System.out.println("caught");e.printStackTrace();}System.out.println("over");}
}
begin
caught
over
java.lang.ArithmeticException: / by zeroat kfm.bases.ErrorAndPxception.ExceptionTryCatch.main(ExceptionTryCatch.java:8)

try-catch语句块首先执行try语句块中的语句,这时可能会出现以下3种情况:

  1. 如果try语句块中的所有语句正常执⾏完毕,没有发⽣异常,那么catch语句块中的所有语句都将被忽略。
  2. 如果try语句块在执⾏过程中发⽣异常,并且这个异常与catch语句块中声明的异常类型匹配,那么try语句块中剩下的代码都将被忽略,⽽相应的catch语句块将会被执⾏。匹配是指catch所处理的异常类型与try块所⽣成的异常类型完全⼀致或是它的⽗类。
  3. 如果try语句块在执⾏过程中发⽣异常,⽽抛出的异常在catch语句块中没有被声明,那么程序⽴即终⽌运⾏,程序被强迫退出。
  • catch语句块中可以加⼊⽤⼾⾃定义处理信息,也可以调⽤异常对象的⽅法输出异常信息,常⽤的⽅法如下:
    • void prinStackTrace() :输出异常的堆栈信息。堆栈信息包括程序运行到当前类的执行流程,它将输出从方法调用处到异常抛出处的方法调用的栈序列。
    • String getMessage() :返回异常信息描述字符串,该字符串描述了异常产生的原因,是 printStackTrace() 输出信息的一部分。

(2)try-catch-finally 处理异常
try-catch-finally 语句块组合使用时,无论 try 块中是否发生异常, finally 语句块中的代码总能被执行。

public class TryCatchFinally {public static void main(String[] args) {try {int i = 1,j = 0, res;System.out.println("bregin");res = i / j;System.out.println("end");} catch (ArithmeticException e) {System.out.println("caught");System.out.println(e.getMessage());  // 异常信息描述字符串e.printStackTrace();  // 输出异常堆栈信息System.out.println("1");} finally {System.out.println("finally");}System.out.println("over");}
}
bregin
caught
/ by zero
java.lang.ArithmeticException: / by zeroat kfm.bases.ErrorAndPxception.TryCatchFinally.main(TryCatchFinally.java:8)
1
finally
over

try-catch-finally语句块执行流程大致分为如下两种情况。

  1. 如果 try 语句块中所有语句正常执⾏完毕,程序不会进⼊ catch 语句块执⾏,但是 finally 语句块会被执⾏。
  2. 如果 try 语句块在执⾏过程中发⽣异常,程序会进⼊到 catch 语句块捕获异常, finally 语句块也会被执⾏。

try-catch-finally 结构中 try 语句块是必须存在的,catchfinally 语句块为可选,但两者⾄少出现其中之⼀。

即使在 catch 语句块中存在 return 语句,finally 语句块中的语句也会执行。发生异常时的执行顺序是,先执行 catch 语句块中 return 之前的语句,再执行 finally 语句块中的语句,最后执行 catch 语句块中的 return 语句退出。
finally 语句块中语句不执行的唯一情况是在异常处理代码中执行了 System.exit(1),退出 java 虚拟机。

public class TryCatchFinallyExit {public static void main(String[] args) {try {int i = 1,j = 0,res;System.out.println("begin");res = i / j;System.out.println("end");} catch (ArithmeticException e) {System.out.println("caught");e.printStackTrace();System.exit(1);} finally {System.out.println("finally");}System.out.println("over");}
}
begin
caught
java.lang.ArithmeticException: / by zeroat kfm.bases.ErrorAndPxception.TryCatchFinallyExit.main(TryCatchFinallyExit.java:8)

System.exit(1) 是一个 Java 中的方法调用,用于终止当前正在执行的 Java 虚拟机(JVM)进程。在调用 System.exit(1) 后,JVM 会立即退出,并返回一个指定的退出状态码 (1 在这里表示非正常退出),0 表示正常退出,非零表示非正常退出。
(3)使用多重 catch 处理异常
当一段代码可能引发多种类型的异常时,可以在一个try语句块后面跟随多个 catch 语句块,分别处理不同类型的异常。一旦系统执行了与异常类型匹配的 catch 语句块,并执行其中的一条 catch 语句后,其后的 catch 语句块将被忽略,程序将继续执行紧随 catch 语句块的代码。

catch 语句块的排列顺序必须是从子类到父类,最后一个一般是 Exception 类。这是因为在异常处理中,catch 语句块会按照从上到下的顺序进行匹配,系统会检测每个 catch 语句块处理的异常类型,并执行第一个与异常类型匹配的 catch 语句块。如果将父类异常放在前面,子类异常的 catch 语句块将永远不会被执行,因为父类异常的 catch 语句块已经处理了异常。

import java.util.InputMismatchException;
import java.util.Scanner;public class MuchCatch {public static void main(String[] args) {Scanner input = new Scanner(System.in);System.out.println("计算开始");int i, j, res;try {System.out.println("请输入被除数");i = input.nextInt();System.out.println("请输入除数");j = input.nextInt();res = i / j;System.out.println("结果为" + res);} catch (InputMismatchException e) {System.out.println("除数和被除数必须为整数");} catch (ArithmeticException e) {System.out.println("除数不能为0");} catch (Exception e) {System.out.println("其他异常" + e.getMessage());} finally {System.out.println("感谢使用本程序");}System.out.println("程序结束");}
}

1.2.3 抛出异常

(1)使用 throws 声明抛出异常
try-catch-finally 处理的是在一个方法内部发生的异常,在方法内部直接捕获并处理。如果在一个方法体内抛出了异常,并希望调用者能够及时地捕获异常,Java 语言中通过关键字 throws 声明某个方法可能抛出的各种异常,以通知调用者。throws 可以同时声明多个异常,之间用逗号隔开。

import java.util.InputMismatchException;
import java.util.Scanner;public class ThrowsExcepton {public static void main(String[] args) {try {divide();} catch (InputMismatchException e) {System.out.println("除数和被除数必须为整数");} catch (ArithmeticException e) {System.out.println("除数不能为0");} catch (Exception e) {System.out.println("其他异常" + e.getMessage());} finally {System.out.println("感谢使用本程序");}System.out.println("程序结束");}// 通过 throws 声明抛出设计时异常public static void divide() throws Exception {Scanner input = new Scanner(System.in);System.out.println("计算开始");int i, j, res;System.out.println("请输入被除数");i = input.nextInt();System.out.println("请输入除数");j = input.nextInt();res = i / j;System.out.println("结果为" + res);}
}

(2)使用 throw 抛出异常
除了系统自动抛出异常外,在编程过程中,有些问题是系统无法自动发现并解决的,如年龄不在正常范围之内,性别输入的不是“男”或“女”等,此时需要程序员而不是系统来自行抛出异常,把问题提交给调用者去解决。在 Java 语言中,可以使用 throw 关键字来自行抛出异常。

throw new Exception("message")

使用 throw 语句抛出异常,让调用者解决异常。

public void divide(int dividend, int divisor) {if (divisor == 0) {throw new ArithmeticException("Cannot divide by zero");} else {int result = dividend / divisor;System.out.println("Result: " + result);}
}public static void main(String[] args) {try {int dividend = 10;int divisor = 0;divide(dividend, divisor);} catch (ArithmeticException e) {System.err.println("Exception caught: " + e.getMessage());}
}
Exception caught: Cannot divide by zero
  • 如果 throw 语句抛出的异常是 Checked 异常,则该 throw 语句要么处于 try 块⾥,显式捕获该异常,要么放在⼀个带 throws 声明抛出的⽅法中,即把该异常交给该⽅法的调⽤者处理;
  • 如果 throw 语句抛出的异常是 Runtime 异常,则该语句⽆须放在 try 块⾥,也⽆须放在带 throws 声明抛出的⽅法中;程序既可以显式使⽤ try…catch来捕获并处理该异常,也可以完全不理会该异常,把该异常交给该⽅法调⽤者处理。

自行抛出Runtime 异常比自行抛出Checked 异常的灵活性更好。同样,抛出 Checked 异常则可以让编译器提醒程序员必须处理该异常。

throw 和 throws 区别

  1. 作⽤不同:throw⽤于程序员⾃⾏产⽣并抛出异常,throws⽤于声明该⽅法内抛出了异常。
  2. 使⽤位置不同:throw位于⽅法体内部,可以作为单独的语句使⽤;throws必须跟在⽅法参数列表的后⾯,不能单独使⽤。
  3. 内容不同:throw抛出⼀个异常对象,只能是⼀个;throws后⾯跟异常类,可以跟多个。

1.2.4 自定义异常

在 Java 中,我们可以通过定义自己的异常类来表示特定的错误情况和处理方式。自定义异常类通常包含以下内容:

  1. 定义异常类,并继承 Exception 或者 RunTimeException
  2. 编写异常类的构造方法,向父类构造方法传入异常描述信息,并继承父类的其他实现方法。
  3. 实例化自定义异常对象,并在程序中使用 throw 抛出。
public class MyException extends Exception {private String message;public MyException(String message) {this.message = message;}@Overridepublic String getMessage() {return message;}
}
public void myMethod(int arg) throws MyException {if (arg < 0 || arg > 100) {throw new MyException("Argument out of range");} else {// 执行正常的代码逻辑}
}

使用自定义异常类可以为我们提供更细粒度的错误处理方式,并使代码具有更好的可读性和可维护性。
自定义异常可能是编译时异常,也可以是运行时异常。

  • 如果自定义异常类继承Excpetion,则是编译时异常。
    特点:方法中抛出的是编译时异常,必须在方法上使用throws声明,强制调用者处理。
  • 如果自定义异常类继承RuntimeException,则运行时异常。
    特点:方法中抛出的是运行时异常,不需要在方法上用throws声明。

1.2.5 异常链

在 Java 中,异常链(Exception Chaining)是指将一个异常作为另一个异常的原因而被抛出。通过异常链,我们可以更清晰地了解异常的触发原因,并且可以在捕获异常时获取到完整的异常信息。

在创建异常链时,可以使用以下两种方式之一:

  1. 使用带有 cause 参数的异常构造方法:异常类的构造方法中通常会包含一个带有 cause 参数的重载版本,用于指定异常的原因。

    public MyException(String message, Throwable cause) {super(message, cause);
    }
    

    在这种情况下,可以将一个异常对象作为 cause 参数传递给当前异常的构造方法。

  2. 使用 initCause 方法:Throwable 类提供了 initCause 方法,用于将异常对象设置为另一个异常的原因。

    try {// ...
    } catch (Exception e) {MyException ex = new MyException("Custom exception");ex.initCause(e);throw ex;
    }
    

    在这种情况下,我们首先创建一个新的异常对象,然后使用 initCause 方法将之前捕获的异常对象设置为其原因。

public class TryDemoFive {public static void main(String[] args) {try {testThree();} catch (Exception e) {
//            e.printStackTrace();System.out.printf( e.getMessage());}}public static void testOne() throws Exception {throw new Exception("第一个异常");}public static void testTwo() throws Exception {try {testOne();} catch (Exception e) {System.out.println(e.getCause());throw new Exception("我是新产生的异常1", e);}}public static void testThree() throws Exception {try {testTwo();} catch (Exception e) {System.out.println(e.getCause());Exception exception = new Exception("新产生的异常2");exception.initCause(e);throw exception;}}
}
null
java.lang.Exception: 第一个异常
新产生的异常2

通过使用异常链,可以在异常处理过程中保留和传递更多的信息,使开发人员能够更好地理解异常的来源和根本原因。

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

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

相关文章

论文阅读 FCOS: Fully Convolutional One-Stage Object Detection

文章目录 FCOS: Fully Convolutional One-Stage Object DetectionAbstract1. Introduction2. Related Work3. Our Approach3.1. Fully Convolutional One-Stage Object Detector3.2. Multi-level Prediction with FPN for FCOS3.3. Center-ness for FCOS 4. Experiments4.1. Ab…

Jmeter和Postman那个工具更适合做接口测试?

软件测试行业做功能测试和接口测试的人相对比较多。在测试工作中&#xff0c;有高手&#xff0c;自然也会有小白&#xff0c;但有一点我们无法否认&#xff0c;就是每一个高手都是从小白开始的&#xff0c;所以今天我们就来谈谈一大部分人在做的接口测试&#xff0c;小白变高手…

【单片机】有人 WH-LTE-7S1 4G cat1 模块,HTTPD模式,字符串传输,文件传输。GPRS模块连接服务器教程。

文章目录 1、配置模块为HTTPD模式 POST字符串传输2、配置模块为HTTPD模式 GET请求3、 上一篇文章&#xff1a;https://qq742971636.blog.csdn.net/article/details/132571592 在上一篇文章里&#xff0c;已经通过TCP 长链接进行服务器与Cat1 GPRS 模块进行双向通信。已经能够满…

(一)SpringBoot 整合WebSocket 前端 uniapp 访问

第一次使用WebSocket&#xff0c;所以最需要一个及其简单的例子&#xff0c;跑通之后&#xff0c;增加自己对该技术的理解。&#xff08;技术基础介绍就免掉了&#xff0c;后面再补&#xff09; 案例逻辑&#xff1a;目前只有一个用户&#xff0c;而且是一个用户给服务器发送数…

Python 画多个子图函数 subplot

子图函数 subplot 若要 pyplot 一次生成多个图形&#xff0c;一般要用到subplot函数&#xff0c;另外还有一个subplots函数。两个函数比较接近但略有区别&#xff0c;限于篇幅&#xff0c;我们只介绍 subplot函数&#xff0c;它的基本语法如下&#xff1a; ax plt.subplot(n…

搬家快递服务小程序的便利性

在当今快节奏的生活中&#xff0c;搬家可能是很多人都需要面对的问题。无论是新房子还是新办公室&#xff0c;都需要高效、便捷的搬家服务。本文将介绍如何使用第三方小程序制作平台&#xff0c;如乔拓云平台&#xff0c;开发一款高效便捷的搬家服务小程序。 1. 注册登录第三方…

模拟实现应用层协议

模拟实现应用层协议 文章目录 模拟实现应用层协议应用层再谈协议 序列化和反序列化 网络版计算器自定义协议利用Json进行序列化和反序列化json库的安装条件编译 应用层 应用层&#xff08;Application layer&#xff09;是OSI模型的第七层。应用层直接和应用程序接口并提供常见…

AI:05 - 基于深度学习的道路交通信号灯的检测与识别

随着人工智能的快速发展,基于深度学习的视觉算法在道路交通领域中起到了重要作用。本文将探讨如何利用深度学习技术实现道路交通信号灯的检测与识别,通过多处代码实例展示技术深度。 道路交通信号灯是指示交通参与者行驶和停止的重要信号。准确地检测和识别交通信号灯对于智…

06.sqlite3学习——DQL(数据查询)(全)

目录 SQLite——DQL&#xff08;数据查询&#xff09; 数据集 select语句 条件查询 比较 确定范围 确定集合 like 查询记录 查询不重复的记录 排序和限制 排序 限制 聚合 聚合函数 语法 SQLite Group By详解 语法 实例 SQLite Having 子句 语法 实例 多…

Linux通信--构建进程通信System-V 消息队列|信号量

文章目录 目录 一、消息队列 二、信号量 1.互斥 2.信号量 一、消息队列 消息队列提供了从一个进程向另一个进程发送数据块的方法每个数据块都被认为是有一个类型&#xff0c;接收者进程接收的数据块可以有不同的类型值IPC资源必须删除&#xff0c;不会随进程自动清楚&#…

webrtc-m79-msvc编译H264

0 写在前面 本文主要参考&#xff1a;webrtc 4577版本vs编译_tusong86的博客-CSDN博客 4577也就是m93&#xff0c;由于源码版本的不同&#xff0c;可能存在一定的出入&#xff0c;可根据实际情况进行修改&#xff1b; 感谢作者的付出&#xff1b; 1 编译参数 powershell运…

【git】Idea撤回本地分支、或远程分支提交记录的各种实际场景操作步骤

文章目录 idea撤回本地分支、远程分支场景操作集合场景1&#xff1a;要撤回最后一次本地分支的提交实现效果&#xff1a;操作步骤&#xff1a; 场景2&#xff1a;要撤回最后一次远程分支的提交有撤销记录的&#xff1a;实现效果&#xff1a;操作步骤&#xff1a; 无撤销记录的&…

数据分析基础-数据可视化学习笔记03-可视化的符号与表示-图形符号学

概念 图型符号学&#xff08;Cartographic Symbolization&#xff09;是地图学领域中的一个重要概念&#xff0c;涉及到如何使用不同的符号、颜色、图案和标记来在地图上表示地理信息和数据。图型符号学旨在传达地理信息&#xff0c;使得地图能够清晰、有效地传达各种空间数据…

微信小程序scroll-view隐藏滚动条参数不生效问题

如题&#xff0c;先来看看问题是怎么出现的。 先看文档如何隐藏滚动条&#xff1a; 再根据文档实现wxml文件&#xff1a; <scroll-view show-scrollbar"{{false}}" enhanced><view wx:for"{{1000}}">11111</view> </scroll-view>…

pytorch异常——RuntimeError:Given groups=1, weight of size..., expected of...

文章目录 省流异常报错异常截图异常代码原因解释修正代码执行结果 省流 nn.Conv2d 需要的输入张量格式为 (batch_size, channels, height, width)&#xff0c;但您的示例输入张量 x 是 (batch_size, height, width, channels)。因此&#xff0c;需要对输入张量进行转置。 注意…

探索未知世界:桌面端3D GIS引领地理信息新时代

近年来&#xff0c;桌面端的三维地理信息系统&#xff08;3D GIS&#xff09;在地理信息领域迎来了显著的发展&#xff0c;为我们带来了更深入、更丰富的地理空间认知和数据分析体验。从城市规划到环境保护&#xff0c;从资源管理到应急响应&#xff0c;桌面端的3D GIS正逐渐成…

day 30 动态GDP柱状图绘制

列表.sort(key选择排序依据的函数&#xff0c;reverseTrue|False) 参数key:要求传入一个函数&#xff0c;表示将列表的每一个元素传入函数当中&#xff0c;返回排序的依据&#xff0c; 参数reverse,是否反转排序结果&#xff0c;True降序&#xff0c;False升序 my_list [[&…

【爬虫小知识】如何利用爬虫爬网页——python爬虫

前言 网络时代的到来&#xff0c;给我们提供了海量的信息资源&#xff0c;但是&#xff0c;想要获取这些信息&#xff0c;手动一个一个网页进行查找&#xff0c;无疑是一项繁琐且效率低下的工作。这时&#xff0c;爬虫技术的出现&#xff0c;为我们提供了一种高效的方式去获取…

Android JNI系列详解之生成指定CPU的库文件

一、前提 这次主要了解Android的cpu架构类型&#xff0c;以及在使用CMake工具的时候&#xff0c;如何指定生成哪种类型的库文件。 如上图所示&#xff0c;是我们之前使用CMake工具默认生成的四种cpu架构的动态库文件&#xff1a;arm64-v8a、armeabi-v7a、x86、x86_64&#xff0…

【附安装包】MyEclipse2019安装教程

软件下载 软件&#xff1a;MyEclipse版本&#xff1a;2019语言&#xff1a;简体中文大小&#xff1a;1.86G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.5GHz 内存4G(或更高&#xff09;下载通道①百度网盘丨下载链接&#xff1a;https://pan.baidu.co…