Java series - Exception

10 minutes reading time

In Java, Exception is listed as a separate chapter, which is enough to prove its independence and importance. So what is an exception?

The basic philosophy of Java is that "poorly structured code doesn't run".

For program Error, recovering system Error is very important, and Exception 作为一种对 Error 改善的机制it can be extremely important 提高代码健壮性.

For Exception , it is naturally the best time to find it during compilation, because at this time we can immediately change the code to improve robustness to solve the problem.

However, some errors are run-time errors RuntimeException, and such hidden dangers can only be discovered when the program is run in the JVM after the program is compiled. Then at this time, there needs to be a way to transmit the wrong information so that the receiver can receive the information in order to locate the problem and solve the problem.

Exception 就是这样一种错误报告机制

basic exception

For exceptions, according to the exceptional condition (exceptional condition), it can be divided into two situations:

  • Common problem: enough information is available in the current environment to always handle this error. That is, you can modify the code so that this problem will not happen again.
  • Abnormal problem: Our code cannot continue to execute due to the lack of certain information data in the current environment (code block). That is, the code will fail under certain circumstances.

At this time, for abnormal problems, all you can do is to jump out of the current environment and submit the problem to the upper-level environment. That's what happens when an exception is thrown.

When an exception is thrown, several things happen.

First, like other object creation in Java, we will use the keyword newto create the exception object on the heap. Then, the current path of execution (which cannot continue) is terminated, and the reference to the exception object is popped from the current environment. At this point, the exception handling mechanism takes over the program and starts looking for an appropriate place to continue program execution. This appropriate place is the exception handler, whose task is to recover the program from an error state so that the program can either run in another way or continue to run.

Here's a simple example that throws an exception:

if( obj == null ){
    
    
  throw new NullPointerException();
}

It means that the current code may appear that obj is empty. When this happens, because of the " throw throw " operation, it can be received and handled elsewhere (described later) information.
So, in the current environment (code block), we no longer have to worry about the fact that obj may be empty, it will be processed elsewhere.

unusual parameters

As with other objects in Java, we always use the keyword newto create exception objects on the heap, which is accompanied by storage allocation and constructor calls.

All standard exception classes have two constructors: one is a no-argument constructor ; the other is a constructor that accepts a string as a parameter so that relevant information can be put into the exception object:

throw new NullPointerException("t = null");

exception handler

As mentioned earlier, the thrown exception will be handled in other "places", and this other place is called "exception handler". Among them try{}catch(e){}is catch块the exception handler

try {
    
    
    // 可能产生异常的代码
    int x = 1;
    int y = x/0;

} catch(Type1 id1) {
    
    
    // 异常处理程序:专用于处理类型Type1的异常
    onMyException1();
} catch(Type2 id2) {
    
    
    // 异常处理程序:专用于处理类型Type2的异常
    onMyException2();
} catch(Type3 id3) {
    
    
    // 异常处理程序:专用于处理类型Type3的异常
    onMyException3();
} finally {
    
    
    // 总会执行
    customExceptionHandler();
}

Practice: exceptions in spring

In the spring framework, spring has abstracted and encapsulated exceptions, which is convenient for us to manage and create exception handlers. You don't want to see the code, here is a try...catch, there is a try...catch, right?

Spring provides a variety of solutions to handle exceptions, you only need to remember @ControllerAdvice this one.

  1. @ControllerAdviceClasses marked by GlobalExceptionHandlerare called global exception handlers. Look at the above, there can be multiple catch blocks, and they are used to handle different exceptions.
  2. Therefore, we can create multiple exception handlers to customErrorHandler(), onMyException11(),onMyException2()specialize in handling different types of exceptions. Among them, customErrorHandler is used to return data in a unified format.

Next, a general example is given:

@ControllerAdvice
public class GlobalExceptionHandler {
    
    

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
    
    }

    /**
     * 把值绑定到Model中,使再controller中可以通过 @RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
    
    
        model.addAttribute("author", "ifredom");
    }

    /**
     * 所有异常都返回统一的json数据
     * @param CustomException
     */
    @ResponseBody
    @ExceptionHandler(value = CustomException.class)
    public Map<String,Object> customErrorHandler(CustomException ex) {
    
    
        Map<String,Object> map = new HashMap<>(16);
        map.put("code", ex.getCode());
        map.put("msg", ex.getMessage());
        return map;
    }

    @ExceptionHandler(value = {
    
    MyCustomException1.class})
    public void onMyException1(){
    
    
        // 处理 MyCustomException1 这种异常
    }

    @ExceptionHandler(value = {
    
    MyCustomException2.class})
    public void onMyException2(){
    
    
       // 处理 MyCustomException2 这种异常
    }

    /**
     * 处理 MethodArgumentNotValidException, BindException 这两种异常
     * 解释:利用 jackson 对请求参数进行校验
     */
    @ExceptionHandler(value= {
    
    MethodArgumentNotValidException.class , BindException.class})
    public String onException(Exception e) throws JsonProcessingException {
    
    
        BindingResult bindingResult = null;
        if (e instanceof MethodArgumentNotValidException) {
    
    
            bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
        } else if (e instanceof BindException) {
    
    
            bindingResult = ((BindException)e).getBindingResult();
        }
        Map<String,String> errorMap = new HashMap<>(16);
        assert bindingResult != null;
        bindingResult.getFieldErrors().forEach((fieldError)->
                errorMap.put(fieldError.getField(),fieldError.getDefaultMessage())
        );
        return objectMapper.writeValueAsString(errorMap);
    }
}
// 自定义一种异常类型
public class CustomException extends RuntimeException{
    
    
    private static final long serialVersionUID = 1L;

    private Integer code;
    private String message;

    public CustomException(String message){
    
    
        this.message = message;
    }
    public CustomException(String message, Integer code){
    
    
        this.message = message;
        this.code = code;
    }
    public CustomException(String message, Throwable e){
    
    
        super(message, e);
        this.message = message;
    }
    public MyCustomException(String message, int code, Throwable e) {
    
    
        super(message, e);
        this.message = message;
        this.code = code;
    }
    @Override
    public String getMessage(){
    
    
        return message;
    }
    public Integer getCode(){
    
    
        return code;
    }
}

// 自定义一种异常类型
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
class MyCustomException1 extends RuntimeException{
    
    
    private String message;
    public MyCustomException() {
    
    }
    public MyCustomException(String message) {
    
    
        this.message = message;
    }
}
// 自定义一种异常类型
@ResponseStatus(value = HttpStatus.FORBIDDEN)
class MyCustomException2 extends RuntimeException{
    
    
    private String message;
    public MyCustomException() {
    
    }
    public MyCustomException(String message) {
    
    
        this.message = message;
    }
}

Now that the definition of the exception has been completed, start the application access next localhost:8080/user, and you will find that the exception has been intercepted.

HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 19 Oct 2022 06:25:33 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
    
    
  "msg": "here",
  "code": 500
}
@RestController
public class UserController {
    
    
    @GetMapping("/user")
    public void registerUser( @ModelAttribute("author") String author){
    
    

        System.out.println(author);
        throw new MyCustomException("hehhe");
    }
}

sometimes. If you don't need to return json data, but you want to render a page template and return it to the browser. Then you can use this class ModelAndView;

@ExceptionHandler(value = MyException.class)
public ModelAndView myErrorHandler(MyException ex) {
    
    
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("error");
    modelAndView.addObject("code", ex.getCode());
    modelAndView.addObject("msg", ex.getMsg());
    return modelAndView;
}

Supplement: If all exception handling returns json, you can use @RestControllerAdvice instead of @ControllerAdvice, so that you don't need to add @ResponseBody on the method.

Extended reading


------ If the article is useful to you, thank you in the upper right corner >>> Like | Favorite<<<

Guess you like

Origin blog.csdn.net/win7583362/article/details/127408043