Java RuntimeException 类
最后修改时间:2025 年 4 月 13 日
java.lang.RuntimeException 类是 Java 中所有未检查异常的超类。与已检查异常不同,RuntimeException 不需要在使用它们的方法签名中声明或显式捕获。
RuntimeException 通常指示应该修复而不是捕获的编程错误。常见示例包括 NullPointerException、ArrayIndexOutOfBoundsException 和 IllegalArgumentException。理解 RuntimeException 对于编写健壮的 Java 程序至关重要。
RuntimeException 基础
RuntimeException 是 Exception 的一个子类,但不同之处在于它是未检查的。 这意味着编译器不会强制处理或声明这些异常。 它们通常代表可以避免的问题。
public class RuntimeException extends Exception {
public RuntimeException() {...}
public RuntimeException(String message) {...}
public RuntimeException(String message, Throwable cause) {...}
public RuntimeException(Throwable cause) {...}
protected RuntimeException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {...}
}
上面的代码显示了 RuntimeException 中可用的构造函数。 这些构造函数允许创建带有消息、原因以及控制堆栈跟踪行为的异常。
基本 RuntimeException 示例
此示例演示了创建和抛出一个基本的 RuntimeException。 当在简单的验证方法中检测到无效输入时,我们会抛出它。
package com.zetcode;
public class Main {
public static void validateAge(int age) {
if (age < 0) {
throw new RuntimeException("Age cannot be negative");
}
System.out.println("Valid age: " + age);
}
public static void main(String[] args) {
try {
validateAge(-5); // This will throw RuntimeException
} catch (RuntimeException e) {
System.out.println("Caught exception: " + e.getMessage());
}
validateAge(25); // This will pass validation
}
}
在此示例中,当提供负年龄时,我们会抛出一个 RuntimeException。 虽然我们在 main 中捕获了它,但请注意,捕获 RuntimeException 是可选的。 第二次调用显示了使用正年龄的成功验证。
自定义 RuntimeException
创建自定义 RuntimeException 允许进行更具体的错误处理。 此示例显示了用于无效帐户操作的自定义异常。
package com.zetcode;
class InsufficientFundsException extends RuntimeException {
public InsufficientFundsException(String message) {
super(message);
}
}
class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void withdraw(double amount) {
if (amount > balance) {
throw new InsufficientFundsException(
"Only " + balance + " available. Tried to withdraw " + amount);
}
balance -= amount;
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount(100);
try {
account.withdraw(150);
} catch (InsufficientFundsException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
在这里,我们定义了扩展 RuntimeException 的 InsufficientFundsException。 当提款超过余额时,BankAccount 会抛出它。 这提供了清晰的、特定于域的错误信息,同时保持未检查状态。
带有 Cause 的 RuntimeException
RuntimeException 可以使用 cause 参数包装其他异常。 当在保留原始错误的同时将已检查的异常转换为未检查的异常时,这非常有用。
package com.zetcode;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
class FileReadException extends RuntimeException {
public FileReadException(String message, Throwable cause) {
super(message, cause);
}
}
public class Main {
public static String readFile(String path) {
try {
return new String(Files.readAllBytes(Paths.get(path)));
} catch (IOException e) {
throw new FileReadException("Failed to read file: " + path, e);
}
}
public static void main(String[] args) {
try {
String content = readFile("nonexistent.txt");
System.out.println(content);
} catch (FileReadException e) {
System.out.println("Error: " + e.getMessage());
System.out.println("Original cause: " + e.getCause().getMessage());
}
}
}
此示例显示了如何将 IOException 包装在我们自定义的 FileReadException 中。 原始异常作为原因被保留,在避免已检查异常要求的同时提供完整的错误上下文。
ArrayIndexOutOfBoundsException
ArrayIndexOutOfBoundsException 是一种常见的 RuntimeException,当访问无效的数组索引时抛出。 此示例演示了它如何发生。
package com.zetcode;
public class Main {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
try {
System.out.println(numbers[3]); // Invalid index
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Caught exception: " + e);
System.out.println("Array length: " + numbers.length);
}
// Safe access with bounds checking
int index = 3;
if (index >= 0 && index < numbers.length) {
System.out.println(numbers[index]);
} else {
System.out.println("Invalid index: " + index);
}
}
}
第一次尝试访问一个包含 3 个元素的数组中的索引 3,导致异常。 第二部分显示了正确的边界检查以防止异常。 在访问之前,始终验证数组索引。
NullPointerException
NullPointerException 发生在尝试在需要对象的地方使用 null 时。 此示例显示了常见的情况和预防技术。
package com.zetcode;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Main {
public static void main(String[] args) {
Person person = null;
try {
System.out.println(person.getName()); // Throws NPE
} catch (NullPointerException e) {
System.out.println("Caught NPE: " + e);
}
// Safe alternatives
person = new Person("Alice");
if (person != null) {
System.out.println(person.getName());
}
// Java 8+ Optional alternative
java.util.Optional.ofNullable(person)
.ifPresent(p -> System.out.println(p.getName()));
}
}
该示例显示了在 null 上调用方法时出现的 NullPointerException。 然后,我们演示了 null 检查和 Java 8 的 Optional 作为更安全的选择。 在使用之前,始终验证对象是否为 null。
IllegalArgumentException
抛出 IllegalArgumentException 指示非法或不适当的参数。 此示例验证了方法参数。
package com.zetcode;
class Calculator {
public static double divide(double dividend, double divisor) {
if (divisor == 0) {
throw new IllegalArgumentException("Divisor cannot be zero");
}
return dividend / divisor;
}
}
public class Main {
public static void main(String[] args) {
try {
double result = Calculator.divide(10, 0);
System.out.println("Result: " + result);
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
// Valid case
double validResult = Calculator.divide(10, 2);
System.out.println("Valid result: " + validResult);
}
}
Calculator 类抛出 IllegalArgumentException 以表示除以零。 这清楚地将无效输入传达给调用者。 main 方法演示了错误和成功案例。
ConcurrentModificationException
当在迭代集合时修改集合时,会发生 ConcurrentModificationException。 此示例显示了问题和解决方案。
package com.zetcode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> colors = new ArrayList<>();
colors.add("Red");
colors.add("Green");
colors.add("Blue");
try {
// This will throw ConcurrentModificationException
for (String color : colors) {
if (color.equals("Green")) {
colors.remove(color);
}
}
} catch (Exception e) {
System.out.println("Caught: " + e);
}
// Safe removal using Iterator
Iterator<String> iterator = colors.iterator();
while (iterator.hasNext()) {
String color = iterator.next();
if (color.equals("Green")) {
iterator.remove();
}
}
System.out.println("Modified list: " + colors);
}
}
第一次尝试在迭代期间修改列表,导致异常。 第二种方法使用 Iterator 的 remove 方法安全地删除元素。 在迭代期间修改集合时,始终使用正确的技术。
来源
本教程介绍了 RuntimeException 以及演示常见场景的实际示例。 理解这些异常有助于编写更健壮的 Java 代码,从而正确处理错误条件。
作者
列出所有Java教程。