一篇文章带你基本理解Java中的异常处理—菜鸟教程
基本概念:
异常是什么?(思考30s再往下看)
异常:指的是java程序在执行过程中可能会出现的错误或者异常情况。
当程序发生异常时,会抛出一个异常对象,并且程序会中断当前的正常执行流程,转而处理异常。
异常分为两种类型:已检查异常(Checked Exception)和未检查异常(Unchecked Exception)
- **已检查异常(Checked Exception):**这些异常在编译时就需要进行处理,否则代码无法通过编译。已检查异常通常表示程序可以预见并且应该能够处理的异常情况。例如,FileNotFoundException、IOException、SQLException等等。
- **未检查异常(Unchecked Exception):**这些异常在编译时不需要进行强制处理,可以选择处理或者不处理。**未检查异常通常表示程序无法恢复的错误或者意外情况。**例如,NullPointerException、ArrayIndexOutOfBoundsException等。
- **运行时异常(Runtime Exception):该异常属于未检查异常,编译时不需要进行强制处理。运行时异常通常表示程序发生了意外的错误或异常情况,是由程序逻辑错误引起的。**例如,NullPointerException、ArrayIndexOutOfBoundsException等。
- **错误(Error):错误属于未检查异常,表示严重的问题,通常无法恢复,表示出现系统级的问题或资源不足的情况。错误不应该被捕获和处理,而是应该由系统来处理。**例如,OutOfMemoryError、StackOverflowError等。
Exception 类的层次
所有的异常类是从 java.lang.Exception 类继承的子类。
Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。
Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
Error 用来指示运行时环境发生的错误。
例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。
下面是在Java的内置类中的常见异常说明:
Java 内置异常类
Java 语言定义了一些异常类在 java.lang 标准包中。
标准运行时异常类的子类是最常见的异常类。由于 java.lang 包是默认加载到所有的 Java 程序的,所以大部分从运行时异常类继承而来的异常都可以直接使用。
Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。
异常 | 描述 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
异常方法
下面的列表是 Throwable 类的主要方法:
序号 | 方法及说明 |
---|---|
1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
2 | public Throwable getCause() 返回一个 Throwable 对象代表异常原因。 |
3 | public String toString() 返回此 Throwable 的简短描述。 |
4 | public void printStackTrace() 将此 Throwable 及其回溯打印到标准错误流。。 |
5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
6 | public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |
异常的处理可以通过以下方式来实现(捕获异常):
try-catch语句块:
使用try-catch语句块可以捕获并处理异常。在try块中包含可能抛出异常的代码,而catch块用于捕获并处理异常。可以有多个catch块来捕获不同类型的异常,也可只有一个。
finally关键字
用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下:
try {// 可能抛出异常的代码
} catch (ExceptionType1 e1) {// 处理异常类型1
} catch (ExceptionType2 e2) {// 处理异常类型2
} finally {// 可选的finally块,用于执行无论是否发生异常都需要执行的代码
}
throws/throw关键字:
在Java中,throw
和throws
都与异常相关,但用法和作用略有不同。
throw关键字用于在代码中抛出异常,而 throws 关键字用于在方法声明中指定可能会抛出的异常类型。
throw
关键字:
throw
关键字用于手动在当前方法中抛出异常对象。当程序的某个条件满足时,可以使用throw
关键字创建并抛出一个异常对象。被抛出的异常会在运行时传播到调用栈的上层,并且需要使用try-catch
语句块或继续使用throws
将异常传递给上层方法进行处理。
示例:
public void method() throws SomeException {if (condition) {throw new SomeException("This is an exceptional situation.");}
}
throws
关键字:
throws
关键字用于在方法声明中指定可能抛出的异常类型。当某个方法可能抛出某种类型的异常时,可以在方法声明中使用throws
关键字列出这些异常类型,以通知调用者进行相应的异常处理。
示例:
public void method() throws SomeException, AnotherException {// 方法实现
}
调用该方法的代码需要对可能抛出的异常进行处理,要么使用try-catch
语句块捕获异常并处理,要么继续使用throws
关键字将异常传递给上层调用者。
总结:
throw
用于手动在方法内抛出异常对象。throws
用于方法声明中指定可能抛出的异常类型,以通知调用者进行处理。
try-with-resources
JDK7 之后,Java 新增的 try-with-resource 语法糖来打开资源,并且可以在语句执行完毕后确保每个资源都被自动关闭 。
try-with-resources 是一种异常处理机制,它可以简化资源管理代码的编写。
JDK7 之前所有被打开的系统资源,比如流、文件或者 Socket 连接等,都需要被开发者手动关闭,否则将会造成资源泄露。
对于实现AutoCloseable接口的资源,可以使用try-with-resources语句来自动关闭资源。这样可以确保资源在使用完毕后被正确地关闭,无需手动处理。
即注意:try-with-resources 语句关闭所有实现 AutoCloseable 接口的资源。
try (Resource res = new Resource()) {// 使用资源的代码,也可处理多个资源,只需要用分号;分隔各个资源即可
} catch (Exception e) {// 处理异常
}
通过合理处理异常,程序可以在遇到错误或异常时进行优雅的处理,提高代码的可靠性和健壮性。
声明自定义异常
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
可以像下面这样定义自己的异常类:
class MyException extends Exception{ }
只继承Exception 类来创建的异常类是检查性异常类。
下面的 InsufficientFundsException 类是用户定义的异常类,它继承自 Exception。
一个异常类和其它任何类一样,包含有变量和方法。
实例
以下实例是一个银行账户的模拟,通过银行卡的号码完成识别,可以进行存钱和取钱的操作。
InsufficientFundsException.java 文件代码:
// 文件名InsufficientFundsException.java
import java.io.*;
//自定义异常类,继承Exception类
public class InsufficientFundsException extends Exception
{//此处的amount用来储存当出现异常(取出钱多于余额时)所缺乏的钱private double amount;public InsufficientFundsException(double amount){this.amount = amount;} public double getAmount(){return amount;}
}
为了展示如何使用我们自定义的异常类,
在下面的 CheckingAccount 类中包含一个 withdraw() 方法抛出一个 InsufficientFundsException 异常。
CheckingAccount.java 文件代码:
// 文件名称 CheckingAccount.java
import java.io.*;//此类模拟银行账户
public class CheckingAccount
{//balance为余额,number为卡号private double balance;private int number;public CheckingAccount(int number){this.number = number;}//方法:存钱public void deposit(double amount){balance += amount;}//方法:取钱public void withdraw(double amount) throwsInsufficientFundsException{if(amount <= balance){balance -= amount;}else{double needs = amount - balance;throw new InsufficientFundsException(needs);}}//方法:返回余额public double getBalance(){return balance;}//方法:返回卡号public int getNumber(){return number;}
}
下面的 BankDemo 程序示范了如何调用 CheckingAccount 类的 deposit() 和 withdraw() 方法。
BankDemo.java 文件代码:
//文件名称 BankDemo.java
public class BankDemo
{public static void main(String [] args){CheckingAccount c = new CheckingAccount(101);System.out.println("Depositing $500...");c.deposit(500.00);try{System.out.println("\nWithdrawing $100...");c.withdraw(100.00);System.out.println("\nWithdrawing $600...");c.withdraw(600.00);}catch(InsufficientFundsException e){System.out.println("Sorry, but you are short $"+ e.getAmount());e.printStackTrace();}}
}
编译上面三个文件,并运行程序 BankDemo,得到结果如下所示:
Depositing $500...Withdrawing $100...Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsExceptionat CheckingAccount.withdraw(CheckingAccount.java:25)at BankDemo.main(BankDemo.java:13)
通用异常
-
在Java中,除了自定义异常之外,还有一些通用的异常类,它们都是继承自
Exception
类或其子类。这些通用异常类可用于表示各种常见的异常情况。以下是几个常见的通用异常类:
NullPointerException
(空指针异常):当尝试访问一个空引用时抛出。IllegalArgumentException
(非法参数异常):当传递给方法的参数不合法时抛出。IndexOutOfBoundsException
(索引越界异常):当使用无效的索引访问数组、集合或字符串时抛出。ArithmeticException
(算术异常):当发生数学运算错误时抛出,例如除以零。FileNotFoundException
(文件未找到异常):试图打开不存在的文件时抛出。
通用异常中的某些异常是未检查异常(Unchecked Exception),而另一些是已检查异常(Checked Exception)。
未检查异常是指在编译时不需要强制捕获或声明的异常。常见的未检查异常包括NullPointerException
、IllegalArgumentException
、IndexOutOfBoundsException
和ArithmeticException
等。在使用这些异常时,编译器不会强制要求进行异常处理,而是留给开发者自行决定是否处理这些异常。
已检查异常是指在编译时需要强制捕获或在方法签名中声明的异常。例如,FileNotFoundException
是一个已检查异常。在使用已检查异常时,开发者必须显式处理并捕获这些异常,否则代码将无法通过编译。
无论是未检查异常还是已检查异常,它们都可以通过throws
关键字声明在方法的声明中,以将异常抛给调用者处理,或者通过try-catch
语句块在代码中进行异常处理。
结尾语:记录于2023年7月31号21时00分,以上仅为个人在Java异常处理—菜鸟教程的学习过程中遇到的问题,还有记录的个人想法,有错误欢迎指出,希望对您有帮助,感谢观看!如果可以的话,点点赞,点点关注,菜鸟基础篇已经完结了,后续会补充其他未补充的知识点!