Java 中的异常处理允许开发人员通过使用 try-catch 块、finally 块、引发异常、自定义异常处理等机制来有效地管理运行时错误。
异常是在程序执行期间(即在运行时)发生的不需要或意外的事件,并中断程序指令的正常流程。当发生意外情况时,例如访问无效索引、除以零或尝试打开不存在的文件,就会发生这种情况。
Java 中的异常是在程序执行过程中发生错误时发生的错误情况。
示例:显示算术异常,或者您可以说除以零异常。
import java.io.*;
class Geeks {
public static void main(String[] args)
{
int n = 10;
int m = 0;
int ans = n / m;
System.out.println("Answer: " + ans);
}
}
输出:
注意:当异常发生且未处理时,程序会突然终止,其后的代码将永远不会执行。
Java 中的异常处理
Java 中的异常处理是管理运行时错误以确保维护应用程序的正常流的有效机制。一些常见的异常示例包括 ClassNotFoundException、IOException、SQLException、RemoteException 等。通过处理这些异常,Java 使开发人员能够创建健壮且具有容错能力的应用程序。
示例:下面的 Java 程序修改了前面的示例,以使用 try-catch 处理 ArithmeticException,最后阻止并保持程序运行。
// Java program to demonstrates handling
// the exception using try-catch block
import java.io.*;
class Geeks {
public static void main(String[] args)
{
int n = 10;
int m = 0;
try {
// Code that may throw an exception
int ans = n / m;
System.out.println("Answer: " + ans);
}
catch (ArithmeticException e) {
// Handling the exception
System.out.println(
"Error: Division by zero is not allowed!");
}
finally {
System.out.println(
"Program continues after handling the exception.");
}
}
}
输出:
Error: Division by zero is not allowed!
Program continues after handling the exception.
注意:借助异常处理,我们可以优雅地检测和处理异常,以便维护程序的正常流程。
注意:即使没有发生异常,finally 块也始终执行,使其成为清理作的可靠位置。
摘要通过下面的视觉辅助工具描述如下:
Java 异常层次结构
所有 exception 和 error 类型都是 Throwable 类的子类,Throwable 是层次结构的基类。一个分支的标题是 Exception。此类用于用户程序应捕获的异常情况。NullPointerException 是此类异常的一个示例。 Java 运行时系统 (JVM) 使用另一个分支 Error 来表示与运行时环境本身 (JRE) 有关的错误。 StackOverflowError 就是此类错误的一个示例。
下图演示了 Java 中的异常层次结构:
发生异常的主要原因
异常可能由于多种原因而发生,例如:
- 用户输入无效
- 设备故障
- 网络连接丢失
- 物理限制(磁盘外内存)
- 代码错误
- 出界
- Null 引用
- 类型不匹配
- 打开不可用的文件
- 数据库错误
- 算术误差
错误表示不可恢复的情况,例如 Java 虚拟机 (JVM) 内存不足、内存泄漏、堆栈溢出错误、库不兼容、无限递归等。错误通常超出程序员的控制范围,我们不应该尝试处理错误。
异常与错误之间的区别
方面 | 错误 | 例外 |
---|---|---|
定义 | Error 表示合理的应用程序不应尝试捕获的严重问题。 | Exception 指示合理的应用程序可能尝试捕获的条件 |
原因 | 由 JVM 或硬件问题引起。 | 由程序中的条件引起,例如无效的输入或逻辑错误。 |
例子 | OutOfMemoryError (内存错误);StackOverFlowError | IOException;NullPointerException 异常 |
要了解 Exception 和 Errors 之间的更多区别,请参阅这篇文章:Java 中的异常与错误。
Java 异常的类型
Java 定义了与其各种类库相关的几种类型的异常。Java 还允许用户定义他们的 it’s exceptions。
异常可以通过两种方式进行分类:
- 内置异常
- 检查的异常
- 未选中的异常
- 用户定义的异常
1. 内置异常
内置异常是 Java 提供的预定义异常类,用于处理程序执行过程中的常见错误。
1.1 已检查的异常
已检查的异常称为编译时异常,因为编译器在编译时检查这些异常。下面列出了 Checked Exception 的示例:
- ClassNotFoundException:当程序尝试在运行时加载类但未找到该类时引发,因为它属于、不在正确的位置或项目中缺少该类。
- InterruptedException:当一个线程暂停并且另一个线程中断它时引发。
- IOException:输入/输出作失败时引发
- InstantiationException:当程序尝试创建类的对象但因类是抽象、接口或没有默认构造函数而失败时引发。
- SQLException:当数据库出现错误时引发。
- FileNotFoundException: 当程序尝试打开不存在的文件时引发
1.2 未选中的异常
未检查的异常与检查的异常正好相反。编译器不会在编译时检查这些异常。简单来说,如果一个程序抛出一个未经检查的异常,即使我们没有处理或声明它,该程序也不会给出编译错误。下面列出了 Unchecked Exception 的示例:
- ArithmeticException:当存在非法数学运算时,将引发此错误。
- ClassCastException:当您尝试将对象强制转换为它不属于This 的类时,会抛出它。
- NullPointerException:当您尝试使用 null 对象(例如访问其方法或字段)时,会抛出它
- ArrayIndexOutOfBoundsException:当我们尝试访问具有无效索引的数组元素时,会发生这种情况。
- ArrayStoreException:当您在数组中存储错误类型的对象时,此句柄 happens。
- IllegalThreadStateException:当线程作在其当前状态下不允许时,将引发此事件
2. 用户定义的异常
有时,Java 中的内置异常无法描述某种情况。在这种情况下,用户还可以创建异常,这些异常称为 “用户定义的异常”。
打印异常信息的方法
方法 | 描述 |
---|---|
printStackTrace() | 打印异常的完整堆栈跟踪,包括错误的名称、消息和位置。 |
toString() | 以异常的 Name (名称) 格式打印异常信息。 |
getMessage() | 打印异常的描述。 |
Try-Catch 块
Java 中的 try-catch 块是一种处理异常的机制。try 块包含可能引发异常的代码,而 catch 块用于处理发生异常的异常。
try {
// Code that may throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}
finally 块
finally Block 用于执行重要代码,无论是否发生异常。
注意: finally 块总是在 try-catch 块之后执行。它还用于资源清理。
try {
// Code that may throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}finally{
// cleanup code
}
处理多个异常
我们可以通过使用多个 catch 块来处理 Java 中的多种类型的异常,每个块捕获不同类型的异常。
try {
// Code that may throw an exception
} catch (ArithmeticException e) {
// Code to handle the exception
} catch(ArrayIndexOutOfBoundsException e){
//Code to handle the anothert exception
}catch(NumberFormatException e){
//Code to handle the anothert exception
}
JVM 如何处理异常?
默认异常处理:发生异常时,JVM 会创建一个包含错误名称、描述和程序状态的异常对象。创建 Exception 对象并在运行时系统中处理它称为引发 Exception。可能有一个列表,其中包含为访问发生异常的方法而调用的方法。此有序列表称为 Call Stack。现在将执行以下过程。
- 运行时系统在调用堆栈中搜索 Exception 处理程序
- 它从发生异常的方法开始搜索,然后向后搜索调用堆栈。
- 如果找到处理程序,则向其传递异常。
- 如果未找到处理程序,则默认异常处理程序将终止程序并打印堆栈跟踪。
查看下图以了解调用堆栈的流程。
插图:
class Geeks{
public static void main(String args[])
{
// Taking an empty string
String s = null;
// Getting length of a string
System.out.println(s.length());
}
}
输出:
让我们看一个示例,该示例说明了运行时系统如何在调用堆栈上搜索适当的异常处理代码。
例:
// Class
// ExceptionThrown
class Geeks {
// It throws the Exception(ArithmeticException)
// Appropriate Exception handler is not found
// within this method
static int divideByZero(int a, int b)
{
// this statement will cause ArithmeticException
// (/by zero)
int i = a / b;
return i;
}
// The runTime System searches the appropriate
// Exception handler in method also but couldn't have
// found. So looking forward on the call stack
static int computeDivision(int a, int b)
{
int res = 0;
// Try block to check for exceptions
try {
res = divideByZero(a, b);
}
// Catch block to handle NumberFormatException
// exception doesn't matches with
// ArithmeticException
catch (NumberFormatException ex) {
System.out.println(
"NumberFormatException is occurred");
}
return res;
}
// Found appropriate Exception handler
// i.e. matching catch block.
public static void main(String args[])
{
int a = 1;
int b = 0;
// Try block to check for exceptions
try {
int i = computeDivision(a, b);
}
// Catch block to handle ArithmeticException
// exceptions
catch (ArithmeticException ex) {
// getMessage() will print description
// of exception(here / by zero)
System.out.println(ex.getMessage());
}
}
}
输出:
/ by zero
程序员如何处理异常?
自定义异常处理:Java 异常处理使用五个关键字:try、catch、throw 和 throws,以及 finally。可能导致异常的代码将进入 try 块。如果发生异常,则使用 catch 捕获异常。我们可以使用 throw 手动引发异常,并且方法必须使用 throws 声明它们可以引发的异常。finally 块用于必须在 try 后运行的代码,无论是否发生异常。
提示: 必须通过 try catch finally block 中的控制流才能更好地理解。
需要 try-catch 子句(自定义异常处理)
请考虑下面的程序,以便更好地理解 try-catch 子句。
例:
// Java Program to Demonstrate
// Need of try-catch Clause
class Geeks {
public static void main(String[] args) {
// Taking an array of size 4
int[] arr = new int[4];
// Now this statement will cause an exception
int i = arr[4];
// This statement will never execute
// as above we caught with an exception
System.out.println("Hi, I want to execute");
}
}
输出:
说明:在上面的例子中,定义了一个大小为的数组,即我们只能访问从索引 0 到 3 的元素。但是我们试图访问索引 4 处的元素(错误地),这就是它抛出异常的原因。在这种情况下,JVM 会异常终止程序。语句 System.out.println(“Hi, I want to execute”);永远不会执行。要执行它,我们必须使用 try-catch 处理异常。因此,要继续程序的正常流程,我们需要一个 try-catch 子句。
异常处理的优点
- 预置以完成程序执行
- 易于识别程序代码和错误处理代码
- 误差传播
- 有意义的错误报告
- 识别错误类型