一. 异常类型
1. Exception
Exception 主要分为两种: Runtime Exception,Checked(Compile) Exception.
常见的 Runtime Exception, 有: NullPointerException,ArithmeticException...
常见的 Checked(Compile) Exception, 有: IOException,FileNotFoundException...
所谓 Checked Exception 就是在编译期间, 你必须对某条, 或多条语句进行异常处理, 如: try...catch...,throws 语句.
下面介绍下 Checked Exception 的优缺点:
特点与优点: Java 专有, 体现 Java 的设计哲学, 没有完善错误处理的代码根本就不会给你机会去执行.
缺点:
必须显式捕捉并处理异常, 或显式声明抛出异常, 增加程序复杂度.
若显式抛出异常, 则会增加方法签名与异常的耦合度.
2. Error
Error 主要表示一些虚拟机内部错误, 如: 动态链接失败.
二. 异常处理规则
程序可读性: 避免过度使用异常处理代码, 减少方法签名与异常的耦合度.
异常原始性: 捕获并保留原始异常信息.
异常针对性: 根据业务需求决定如何处理异常, 比如:
当你检查商品库存时发生异常, 此时就应终止此次调用, 并告诉上层用户详细, 明确的原因.
当你获取用户头像失败时, 因为该操作不影响整体订单, 支付流程, 所以不需要终止此次调用, 可与上层用户协商处理, 比如: 返回一个空字符串.
三. 相关问题
throw 与 throws 区别?
位置:
throws 位于方法签名.
throw 位于函数体内.
语法格式
throws 后面跟的是异常类, 且一次可以跟多个, 只需要以逗号分隔.
throw 后面跟着的是异常实例, 且一次只能跟一个.
命中率
throws 只是做个防守, 并不会真正执行.
一旦执行到 throw 语句, 必定抛出异常.
为什么要有异常处理机制?
无法穷举所有的异常情况.
若异常处理的代码过多, 会导致程序可读性变差.
为什么要把原始异常封装一层?
安全性, 防止恶意用户获得系统内部信息.
对上层用户更加友好, 让其更加明确, 详细的知道异常原因.
为什么有那么多类需要实现 Closeable 或 AutoCloseable 接口?
Java9 增强了自动关闭资源的 try 语句.
- public class ExceptionTest {
- public static void readFile(){
- try(BufferedReader bufferedReader = new BufferedReader(new FileReader("justForTest.txt")))
- {
- System.out.println(bufferedReader.readLine());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- @Test
- public void readFileTest(){
- ExceptionTest.readFile(); // Just for test.
- }
四. 实践 (自定义 RuntimeException)
- @Getter
- public class ServiceException extends RuntimeException {
- private HttpStatus status;
- private ResultCode resultCode;
- private Object errorData;
- private ServiceException(HttpStatus status, ResultCode resultCode, Object errorData){
- this.status = status;
- this.resultCode = resultCode;
- this.errorData = errorData;
- }
- public static ServiceException badRequest(ResultCode resultCode, Object errorData){
- return new ServiceException(HttpStatus.BAD_REQUEST, resultCode, errorData);
- }
- }
- @Getter
- public enum ResultCode {
- // errorCode
- SUCCESS(0, "SUCCESS"),
- INVALID_PARAMETER(600, "invalid parameter");
- private final int errorCode;
- private final String errorData;
- ResultCode(int errorCode, String errorData){
- this.errorCode = errorCode;
- this.errorData = errorData;
- }
- }
- @ControllerAdvice
- public class GlobalErrorHandler {
- @ExceptionHandler(ServiceException.class)
- public ResponseEntity<ErrorResponse> handleServiceException(ServiceException ex){
- return ResponseEntity
- .status(ex.getStatus())
- .body(ErrorResponse.failed(ex.getResultCode(), ex.getErrorData()));
- }
- }
- @ApiModel
- @Getter
- public class ErrorResponse<T> implements Serializable {
- private static final long serialVersionUID = -2254339918462802230L;
- private final int errorCode;
- private final String errorMsg;
- private final T errorData;
- private ErrorResponse(ResultCode resultCode, T errorData) {
- this.errorCode = resultCode.getErrorCode();
- this.errorMsg = resultCode.getErrorData();
- this.errorData = errorData;
- }
- public static <T> ErrorResponse<T> failed(ResultCode resultCode, T data){
- return new ErrorResponse(resultCode, data);
- }
- }
- @RestController
- public class OrderController {
- @GetMapping(value = "/v1/orders/{order_id}"/*, produces = {"application/toString", "application/json"}*/)
- public Order getOrder(@PathVariable("order_id") @NotBlank String orderId){
- Order order = new Order();
- BigDecimal total = new BigDecimal(-1.00, new MathContext(2, RoundingMode.HALF_UP));
- if (total.compareTo(BigDecimal.ZERO) <= 0){
- throw ServiceException.badRequest(ResultCode.INVALID_PARAMETER,
- "Total is less than zero!");
- }
- order.setOrderId(orderId);
- order.setTotal(total);
- return order;
- }
- }
五. 参考
疯狂 Java 讲义 (第十章 - 异常处理)
JAVA 核心知识点整理
来源: https://www.cnblogs.com/YaoFrankie/p/11440626.html