网站首页 > 精选教程 正文
异常的定义
在Java中,异常处理是围绕java.lang.Throwable类构建的,它是所有错误或异常的超类。
一、异常根类:Throwable
Throwable类是Java异常体系的根类,所有异常都继承自这个类。它提供了一个错误处理的通用框架,包括获取异常原因、堆栈跟踪信息等方法。
1、关键方法:
- getMessage():返回异常发生时的详细消息。
- getCause():返回导致当前异常的原因。
- toString():返回异常的字符串表示。
- printStackTrace():打印异常及其堆栈跟踪到标准错误流。
二 、异常分类
Throwable有两个主要的子类:Error和Exception。
1、Error
Error类表示编译时或系统错误,通常是不应该被应用程序捕获的严重问题。Error子类表示JVM无法处理的错误,如OutOfMemoryError、StackOverflowError等。
2、Exception
Exception类是程序可以处理的异常。它有两个主要的子类:RuntimeException和所有其他非运行时异常。
2.1、运行时异常 RuntimeException
RuntimeException是那些可能在Java虚拟机正常运行期间发生的异常,通常是由于编程错误导致的。RuntimeException及其子类是未检查异常,编译器不会强制检查它们。
常见的RuntimeException子类包括:
- NullPointerException:尝试使用null的对象引用。
- IndexOutOfBoundsException:索引超出数组界限。
- ArithmeticException:算术运算异常,如除以零。
2.2、非运行时异常 CheckedException
除了RuntimeException之外的所有Exception子类都是检查异常(checked exceptions),编译器会强制要求处理这些异常(通过try-catch或throws关键字)。
常见的非运行时异常包括:
- IOException:输入输出异常。
- SQLException:数据库访问异常。
- MalformedURLException:URL格式不正确。
三、异常实现类结构
Throwable
|
+--- Error
| |
| +--- OutOfMemoryError
| +--- StackOverflowError
| +--- ...
+--- Exception
|
+--- RuntimeException
| |
| +--- NullPointerException
| +--- ArrayIndexOutOfBoundsException
| +--- ...
+--- CheckedException
|
+--- IOException
+--- SQLException
+--- ...
异常处理关键字说明
- try-catch-finally 块是处理异常的基本机制,可以捕获并处理异常,确保代码正常执行或退出。
- try-with-resources 语句简化了资源管理,确保资源在 finally 块中被正确关闭。
- throw 关键字用于手动抛出异常,将错误信息传递给调用者。
- throws 关键字用于声明方法可能抛出的异常,将异常传递给调用者(只能用于方法声明,不能用于代码块)。
1、try-catch-finally块
使用场景
try-catch-finally 块用于捕获和处理异常,确保代码在发生异常时能够正常执行或退出。
- try 块包含可能抛出异常的代码。
- catch 块用于捕获特定类型的异常,每个 try 块可以有多个 catch 块。
- finally 块无论是否发生异常,都会执行的代码,通常用于释放资源,例如关闭文件或数据库连接等。
注意事项
- finally 块中不要使用 return 语句,因为它可能会干扰异常处理流程。
- 如果 finally 块中抛出异常,则会覆盖掉之前捕获的异常。
代码示例
public class Example1 {
public static void main(String[] args) {
try {
int result = 10 / 0; // 抛出 ArithmeticException
} catch (ArithmeticException e) {
System.out.println("除以零错误:" + e.getMessage());
} finally {
System.out.println("finally 块执行");
}
}
}
2、try-with-resources语句
使用场景
try-with-resources 语句简化了资源管理,确保资源在 finally 块中被正确关闭。它适用于需要自动关闭资源的场景,例如文件、网络连接、数据库连接等(Java 7 引入)。
注意事项
- try-with-resources 语句中的资源必须实现 AutoCloseable 接口。
- 资源的关闭操作可能抛出异常,需要使用 try-catch 块来捕获异常
代码示例
import java.io.FileInputStream;
import java.io.IOException;
public class TryWithResourcesExample {
public static void main(String[] args) {
String filePath = "/path/to/file.txt";
try (FileInputStream fis = new FileInputStream(filePath)) {
// 使用 FileInputStream 进行操作
byte[] data = new byte[fis.available()];
fis.read(data);
// 在这里,数据已经被读取,可以进行其他操作
} catch (IOException e) {
System.err.println("读取文件时出错: " + e.getMessage());
}
// FileInputStream 在 try 块结束时自动关闭,无需显式调用 close()
}
}
====== 自定义资源类 ==========
import java.io.Closeable;
import java.io.IOException;
public class CustomResource implements AutoCloseable {
public void operate() {
// 资源操作逻辑
}
@Override
public void close() throws IOException {
// 清理和关闭资源的逻辑
}
}
public class CustomTryWithResourcesExample {
public static void main(String[] args) {
try (CustomResource resource = new CustomResource()) {
resource.operate();
} catch (Exception e) {
System.err.println("资源操作时出错: " + e.getMessage());
}
// CustomResource 在 try 块结束时自动关闭
}
}
FileInputStream、BufferedReader、FileReader 和 CustomResource 都实现了 Closeable 接口(AutoCloseable 是 Closeable 的子接口)。因此,它们都可以在 try-with-resources 语句中使用,确保了资源会被正确关闭。
try-with-resources 语句的工作原理是:当 try 块执行结束时,JVM 会按照它们在 try 括号中的相反顺序自动调用每个资源的 close() 方法。如果在关闭资源的过程中发生了异常,它会与 try 块中抛出的任何异常合并,并重新抛出。如果 try 块中的异常是可控的(checked exception),那么关闭方法中抛出的异常将会被抑制,并作为导致异常的异常的起因(cause)附加上去
3、throw关键字
使用场景
throw 关键字用于手动抛出异常。在程序中,如果遇到无法处理的错误情况,可以使用 throw 关键字抛出异常,将错误信息传递给调用者。
public class Example3 {
public static void checkAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("年龄必须大于18岁");
}
System.out.println("年龄合法");
}
public static void main(String[] args) {
checkAge(15);
}
}
4、throws关键字
使用场景
throws 关键字用于声明方法可能抛出的异常。当一个方法可能抛出异常,但无法处理该异常时,可以使用 throws 关键字声明该异常,将异常传递给调用者。
注意事项
- throws 关键字只能用于方法声明,不能用于代码块。
- 如果方法声明了可能抛出的异常,则调用该方法的代码必须使用 try-catch 块来捕获异常,或者使用 throws 关键字将异常继续传递给调用者。
代码示例
public class Example4 {
public void readFile(String filePath) throws FileNotFoundException {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException("文件不存在: " + filePath);
}
// ... 读取文件内容 ...
}
public static void main(String[] args) {
Example4 example = new Example4();
try {
example.readFile("non_existent_file.txt");
} catch (FileNotFoundException e) {
System.err.println("文件读取错误: " + e.getMessage());
}
}
}
程序中异常处理和设计建议
1. 异常分类和层次结构
- 清晰的分类: 使用特定的异常类来表示不同类型的错误,例如 FileNotFoundException、DatabaseConnectionException 等。这能提供更详细的错误信息,方便调试和修复。
- 层次化结构: 建立异常类的层次结构,例如使用 RuntimeException 表示运行时错误,IOException 表示输入输出错误等。这能方便地进行异常捕获和处理。
- 自定义异常: 自定义异常类可以提供更具体的错误信息,以及更详细的上下文信息,便于错误排查。
2. 异常处理原则
- 不要忽略异常: 不要简单地使用空 catch 块来忽略异常,除非你确定可以安全地忽略它。
- 不要在 catch 块中抛出相同类型的异常: 这会导致异常处理机制失效。
- 不要在 finally 块中使用 return 语句: 可能会干扰异常处理流程。
- 在 finally 块中释放资源: 例如关闭文件、数据库连接等,确保资源被正确释放。
3. 异常处理最佳实践
- 使用 try-with-resources 语句: 它是 Java 7 引入的特性,可以简化资源管理,确保资源在 finally 块中被正确关闭。
- 使用日志记录工具记录异常: 例如 java.util.logging 或第三方日志库,记录异常信息方便调试和排查问题。
- 避免捕获过于宽泛的异常类型: 捕获更具体的异常类型,能更好地定位问题。
- 使用异常链: 在捕获异常后,可以使用 initCause() 方法将原始异常作为导致当前异常的原因保存,方便追踪问题。
4. 异常设计建议
- 异常信息应包含详细信息: 包含错误原因、错误位置、相关参数等信息,方便调试。
- 异常类应该易于理解: 使用描述性的类名和方法名,方便理解异常类型和原因。
- 异常处理应该尽可能地与业务逻辑分离: 不要在业务逻辑中进行大量的异常处理,将异常处理逻辑集中到专门的异常处理类中。
5. 避免过度使用异常
- 异常处理开销: 异常处理会带来一定的性能开销,不要过度使用异常来处理正常情况,例如验证参数合法性。
- 使用其他机制: 对于一些非错误情况,例如验证参数、处理特定情况等,可以使用其他机制,例如返回值、状态码等
项目中自定义异常处理代码示例
1. 创建基础异常类
public class BaseException extends RuntimeException {
private String errorCode;
private String errorMessage;
public BaseException(String errorCode, String errorMessage) {
super(errorMessage);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
public String getErrorCode() {
return errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
}
- 继承 RuntimeException,方便使用。
- 添加 errorCode 和 errorMessage 属性,用于存储错误信息。
- 提供构造函数,方便传递错误信息。
2. 创建具体异常类
public class UserNotFoundException extends BaseException {
public UserNotFoundException(String message) {
super("USER_NOT_FOUND", message);
}
}
public class InvalidPasswordException extends BaseException {
public InvalidPasswordException(String message) {
super("INVALID_PASSWORD", message);
}
}
- 继承 BaseException,方便管理。
- 定义特定异常类型,例如 UserNotFoundException、InvalidPasswordException 等。
- 传递错误信息时,包含 errorCode 和 errorMessage。
3. 定义异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BaseException.class)
public ResponseEntity<ErrorResponse> handleBaseException(BaseException ex, WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(
ex.getErrorCode(),
ex.getErrorMessage()
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception ex, WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(
"SYSTEM_ERROR",
"系统错误,请联系管理员"
);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
- 使用 @ControllerAdvice 注解,全局处理异常。
- 使用 @ExceptionHandler 注解,指定处理的异常类型。
- 针对 BaseException,使用 getErrorCode 和 getErrorMessage 获取错误信息。
- 针对其他异常,返回通用错误信息。
4. 定义 ErrorResponse 类
public class ErrorResponse {
private String errorCode;
private String errorMessage;
public ErrorResponse(String errorCode, String errorMessage) {
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
// ... getter and setter ...
}
- 封装错误状态码和错误信息
- 错误码和错误信息 可以抽象一个功能异常定义枚举类
5. 在业务逻辑中抛出异常
@Service
public class UserService {
public User getUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
return user;
}
public void changePassword(User user, String newPassword) {
if (!passwordValidator.isValid(newPassword)) {
throw new InvalidPasswordException("密码格式不正确");
}
// ... 修改密码逻辑 ...
}
}
- 上一篇: 异常处理,JAVA中异常处理的介绍
- 下一篇: 深入理解java异常处理机制
猜你喜欢
- 2024-11-20 Java中的异常
- 2024-11-20 小白也能看懂的Java异常处理机制
- 2024-11-20 JVM是如何处理各种异常的呢?
- 2024-11-20 Java异常之异常处理类详解和代码举例
- 2024-11-20 第25天|Java入门有野,异常处理
- 2024-11-20 java安全编码指南之:异常处理
- 2024-11-20 解读Java编程思想--异常处理
- 2024-11-20 Java中异常处理机制的详细解析及其优化示例代码
- 2024-11-20 学习java, 需要知道的异常处理
- 2024-11-20 java异常处理
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)