目录
一、定义:
异常(Exception)是在程序执行过程中出现的意外或错误情况。
二、异常的类型
1、检查型异常(Check Exceptions)
定义:这些异常是编译器要求必须处理的异常,(有时候也叫编译器异常或者编译器异常)。它们通常是在程序运行时由于外部因素(如文件不存在、网络连接失败等)导致的可预测的问题。
示例:java.io.FileNotFoundException
。当你试图打开一个不存在的文件时,就会抛出这个异常。例如:
import java.io.File;
import java.io.FileReader;
public class CheckedExceptionExample {
public static void main(String[] args) {
try {
File file = new File("nonexistent.txt");
FileReader reader = new FileReader(file);
} catch (java.io.FileNotFoundException e) {
System.out.println("文件不存在:" + e.getMessage());
}
}
}
在这个例子中,FileReader
构造函数会检查文件是否存在,如果不存在就会抛出FileNotFoundException异常
。因为这是一个检查型异常,所以必须使用try - catch
块来处理它,或者在方法签名中声明该异常(使用throws
关键字)。→这个很关键,是针对所有的检查型异常。
2、运行时异常(Runtime Exceptions)
定义:这些异常是在程序运行时可能发生的逻辑错误。它们通常是由于程序员的错误导致的,例如数组越界、空指针引用等。编译器不会强制要求处理这些异常。
以NullPointerException
(空指针异常)为例:
public class RuntimeExceptionExample {
public static void main(String[] args) {
String str = null;
// 以下代码会抛出NullPointerException
System.out.println(str.length());
}
}
这里试图调用null
对象的length
方法,就会抛出NullPointerException
。因为这是一个运行时异常,即使没有使用try - catch
块处理,代码也能编译通过,但在运行时会出现错误。
3、错误(Errors)
定义:这些是严重的问题,通常是由 Java 虚拟机(JVM)内部的错误或者资源耗尽等情况导致的。程序通常无法从这些错误中恢复,例如 OutOfMemoryError(内存溢出错误)、StackOverflowError(虚拟机栈溢出错误)
。
三、异常处理机制
1、try-catch块
作用:用于捕获和处理异常。try
块中包含可能会抛出异常的代码,catch
块用于捕获特定类型的异常并进行相应的处理。
语法:
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理ExceptionType1类型异常的代码
} catch (ExceptionType2 e2) {
// 处理ExceptionType2类型异常的代码
}
例如,处理多种类型的异常:
try {
int[] arr = new int[5];
System.out.println(arr[10]);
File file = new File("nonexistent.txt");
FileReader reader = new FileReader(file);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界:" + e.getMessage());
} catch (FileNotFoundException e) {
System.out.println("文件不存在:" + e.getMessage());
}
在这个例子中,try
块中有两个可能抛出异常的操作。如果发生数组越界异常,会被第一个catch
块捕获并处理;如果发生文件不存在异常,会被第二个catch
块捕获并处理。
(对于单独的try{……},这里解释一下会自动关闭try块中定义的“资源对象”)
例如:
public static void main(String[] args) {
// try 代码块:
// 作用1:自动关闭Scanner对象
try (Scanner input = new Scanner(System.in)) {
int n1 = input.nextInt();
int n2 = input.nextInt();
int result = n1 /n2;
System.out.printf("%d ÷ %d = %d",n1,n2,result);
}
}
当使用 try (Scanner input = new Scanner(System.in))
这种 try-with-resources
语句时,可以自动关闭 Scanner
对象。当 try
代码块执行结束时,无论是否发生异常,Scanner
对象的 close()
方法都会被自动调用,从而释放资源,防止资源泄漏。这样可以让代码更加简洁和安全,避免忘记调用 close()
方法导致的资源管理问题。
2、finally块
作用:无论try
块中是否抛出异常,finally
块中的代码都会被执行。它通常用于释放资源,如关闭文件、数据库连接等。
语法:
try {
// 可能抛出异常的代码
} catch (Exception e) {
// 处理异常的代码
} finally {
// 总是执行的代码
}
例如:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class FinallyExample {
public static void main(String[] args) {
FileReader reader = null;
try {
File file = new File("test.txt");
reader = new FileReader(file);
// 读取文件内容等操作
} catch (IOException e) {
System.out.println("读取文件出错:" + e.getMessage());
} finally {
if (reader!= null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("关闭文件出错:" + e.getMessage());
}
}
}
}
}
在这个例子中,不管try
块中读取文件是否成功(是否抛出IOException
),finally
块都会尝试关闭FileReader
对象,以释放资源。
3、throws关键字
作用:用于在方法签名中声明该方法可能抛出的异常。这样,调用这个方法的代码就可以选择处理这些异常或者继续向上层抛出。
语法:
public void methodName() throws ExceptionType1, ExceptionType2 {
// 方法体可能抛出ExceptionType1和ExceptionType2类型的异常
}
例如:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class ThrowsExample {
public static void readFile() throws FileNotFoundException {
File file = new File("test.txt");
FileReader reader = new FileReader(file);
}
public static void main(String[] args) {
try {
readFile();
} catch (FileNotFoundException e) {
System.out.println("文件不存在:" + e.getMessage());
}
}
}
在这个例子中,readFile
方法使用throws
关键字声明了可能抛出FileNotFoundException
(检查型异常)。在main
方法中调用readFile
方法时,使用try - catch
块来处理这个可能抛出的异常或者在方法签名中声明该异常(使用throws
关键字)。
四、自定义异常
1、定义:
可以通过继承Exception
(用于检查型异常)或RuntimeException
(用于运行时异常)类来创建自己的异常类。这在需要根据特定的业务逻辑定义异常情况时非常有用。
2、示例:
假设我们要创建一个表示年龄不合法的异常。首先创建一个自定义异常类:
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
然后在一个方法中使用这个自定义异常:
public class CustomExceptionExample {
public static void checkAge(int age) throws InvalidAgeException {
if (age < 0 || age > 150) {
throw new InvalidAgeException("年龄必须在0到150之间");
} else {
System.out.println("年龄合法");
}
}
public static void main(String[] args) {
try {
checkAge(-5);
} catch (InvalidAgeException e) {
System.out.println("年龄不合法:" + e.getMessage());
}
}
}
在这个例子中,checkAge
方法会检查传入的年龄是否合法。如果不合法,就会抛出InvalidAgeException
。因为InvalidAgeException
异常是继承Exception(检查型异常)所以在main
方法中,使用try - catch
块来处理这个自定义异常。