“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
Hi, everyone, I am three days fishing, two days drying net small 66
preface
Welcome to our GitHub repository Star: github.com/bin39232820… The best time to plant a tree was ten years ago, followed by now
Today, the second chapter of the Six-pulse Sword came to ask me questions again, and sent me a bunch of expressions, and I called a dude
Of course, I can’t answer him so, after all, is my few fans, so pay attention to small 66, each of my fans can get my precise care, so ah, returned to its words below
We found no, this time six elder brother tough, no seconds back to the fans, ha ha good guy! Instead of licking the dog, let’s get back to business: here’s how we used to handle exceptions, which is really best practice!
A case study
Yes, this case is a small 66 self experience of an example ha, I think we have used micro service! I say first background, I have such a scene, is I pay is completed, if I was going to deliver the goods to the user, but to the user play before, I need to call out the risk control services, risk control to judge if the users have the risk, I will stop this shipment, because the system is doing the overseas system, I’ll call the risk control system to do such a thing before, is the unity of the overseas local currency into USD exchange rate, this design to the exchange rate of the service, and then one day, if I made some changes, and then I need to pay the service, and I call rate the service of the interface upgrade together, but because I was not careful, and lead to forget hair exchange interface, Then there will be a problem, because I rate the service itself, which is the exception handling, even if I don’t have to upgrade the service, you can also adjust the service, but I will put my own exception into code, and then pay the service call rate, according to the logic code value of the success or failure to do, but because I payment services, If the call is successful, I will pass the converted amount to risk control, if the conversion back to fail, I will give a default value of 0, but the writing logic will run into a problem, there will be risk control strategy, according to the amount it has a strategy is to intercept the amount of 0 orders, not delivery, so that an upgrade, Because this logic led to more than 6 k is not delivery of single delivery, lead to the accident, like the above problem, in fact, we don’t think we should help others to make decisions, said if failure, we should not say to a default value, but cast exception out of that, this is the right way to do it, is a lot of times, We did not know is for a business code errors, or throw an Exception, like many other less rigorous business, may not say so clear, but we have to consider payment must be a little bit is very serious, like this accident, we have a lot of insufficient places, warning not to delay delivery, The call to the exchange rate interface failed, there was no alarm, but the native error was converted and so on. Therefore, small 66 side feel, a lot of times, we really do not know how to deal with some business abnormalities, how to return to other services, so that the people who call your service, think your service design is good, and so on, this is what I want to talk to you about this article.
But let’s take a look at Java’s exception system first.
What is an exception
Exceptions are some errors in a program, but not all errors are exceptions, and errors can sometimes be avoided.
For example, if your code is missing a semicolon, the result is java.lang.Error; If you use the System. The out. Println (11/0), then you because you do with zero divisor, throws Java. Lang. ArithmeticException abnormalities.
Exceptions can occur for many reasons, usually including the following categories:
- The user entered illegal data.
- The file to open does not exist.
- The connection is down during network communication, or the JVM runs out of memory.
To understand how Java exception handling works, you need to understand three types of exceptions:
- Checking exceptions: The most representative checking exceptions are those caused by user errors or problems that the programmer could not have foreseen. For example, when trying to open a nonexistent file, an exception occurs that cannot simply be ignored at compile time.
- Runtime exceptions: Runtime exceptions are exceptions that can be avoided by programmers. In contrast to checking exceptions, runtime exceptions can be ignored at compile time.
- Errors: Errors are not exceptions, but problems outside the programmer’s control. Errors are generally ignored in code. For example, when a stack overflow occurs, an error occurs that is not detected at compile time.
Java exception architecture
Java treats exceptions as objects and defines a base class java.lang.throwable as a superclass for all exceptions.
Many Exception classes have been defined in the Java API, which fall into two broad categories, Error and Exception.
The Java exception hierarchy diagram is shown below:
In Java, the parent of all Exception classes is Throwable, Error is the parent of Error type exceptions, Exception is the parent of Exception type exceptions, RuntimeException is the parent of all runtime exceptions, Classes other than RuntimeException that inherit from Exception are non-runtime exceptions.
Error
:Error
Class objects are generated and thrown by the Java virtual machine, and most errors have nothing to do with what the code writer is doing. For example, the Java virtual machine runs incorrectly (Virtual MachineError
), when the JVM no longer has the memory resources it needs to continue with the operationOutOfMemoryError
. When these exceptions occur, the Java Virtual Machine (JVM) typically selects thread termination; It also happens when the virtual machine tries to execute an application, such as a class definition error (NoClassDefFoundError
), link error (LinkageError
). These errors are not detectable because they are outside the control and processing capabilities of the application, and most of them are not allowed to occur while the program is running. Even if an error does occur, a properly designed application should not, by nature, attempt to handle the exception it raises. In Java, errors are usually usedError
Subclass description of.Exception
In:Exception
There is an important subclass in the branchRuntimeException
This type of exception is automatically defined for the program you writeArrayIndexOutOfBoundsException
(array index out of bounds),NullPointerException
(null pointer exception),ArithmeticException
(arithmetic exception),MissingResourceException
(Lost resources),ClassNotFoundException
(can not find the class) and other exceptions, these exceptions are not checked exceptions, the program can choose to capture processing, can also not handle. These exceptions are generally caused by program logic errors, the program should avoid the occurrence of such exceptions as far as possible from the logical point of view; whileRuntimeException
Exceptions other than exceptions are collectively referred to as non-runtime exceptions and are of typeException
Class and its subclasses are exceptions that must be handled syntactically. If not handled, the program will not compile. Such asIOException
,SQLException
And user – definedException
Exception: Generally, you cannot customize the exception check.
Java exception handling mechanism
Java exception handling is essentially throwing and catching exceptions.
An exception is thrown
To understand throwing exceptions, it is important to understand an exception condition, which is a problem that prevents the current method or scope from continuing to execute. Second, distinguish the exception case from the common problem, which is that there is enough information available in the current environment to always handle the error. In the case of exceptions, you can’t continue because you don’t have the necessary information to solve the problem in the current environment. All you can do is jump out of the current environment and refer the problem to the upper environment, which is what happens when an exception is thrown. After an exception is thrown, several things happen. First, it will be used as a normal Java objectnew
Create an exception object on the heap. Then, the current execution path (which can no longer be continued) is terminated and a reference to the exception object is ejected from the current environment. At this point, the exception handling mechanism takes over and starts looking for a proper place to continue executing the program. This proper place is the exception handler, or exception handler, whose job is to recover the program from its error state so that it can either run in a different way or continue running.
As a simple example, if we create a reference to the Student object Student, stu may not be initialized at the time of the call. You can create an object that represents the error message and throw it out of the current environment, propagating the error message to the larger environment.
if(stu == null){
throw new NullPointerException();
}
Copy the code
- Catch exception: After the method throws an exception, the runtime system turns to finding the appropriate exception handler. A potential exception handler is a collection of methods that remain in turn in the call stack when an exception occurs. An exception handler is a proper exception handler when the type of exception it can handle matches the type of exception thrown by the method. The run-time system starts with the method where the exception occurred and goes back to the methods in the call stack until it finds a method with an appropriate exception handler and executes it. When the runtime system traverses the call stack without finding a suitable exception handler, the runtime system terminates. Also, it means the termination of the Java program.
Java exception processing involves five keywords: try, catch, finally, throw, and throws. Here is a quick introduction to basic exception handling knowledge by understanding these five key words.
• Try — for listening. The code to be listened on (code that might throw an exception) is placed inside the try block, and when an exception occurs within the try block, the exception is thrown. • Catch — Used to catch exceptions. Catch is used to catch exceptions that occur in a try block. • Finally — Finally blocks are always executed. It is primarily used to reclaim physical resources (such as database connections, network connections, and disk files) that are opened in the try block. Only a finally block will return to execute a return or throw statement ina try or catch block. If a statement terminates a method such as a return or throw is used in the finally block, it will not jump back to execution. • Throw — used to throw an exception. • Throws — used in method signatures to declare exceptions that the method may throw.
How do you handle exceptions in a project
Small 66 side is divided into two cases, one is our general background management system, the other is similar to the payment system of the C-end project, and in my opinion, they are different in the fine granularity of exception processing.
The general way of background management system
An exception enumeration class where all exception codes are defined:
Public enum BizExceptionEnum {APPLICATION_ERROR(1000, "Network busy, please try again later "), INVALID_USER(1001," username or password error "), INVALID_REQ_PARAM(1002, "error "), EXAM_NOT_FOUND(1003," Failed to find test information "),; BizExceptionEnum(Integer errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } private final Integer errorCode; private final String errorMsg; // get...... }Copy the code
A business exception class:
public class BizException extends RuntimeException { private final BizExceptionEnum bizExceptionEnum; public BizException(BizExceptionEnum bizExceptionEnum) { super(bizExceptionEnum.getErrorMsg()); this.bizExceptionEnum = bizExceptionEnum; } public BizExceptionEnum getBizExceptionEnum() { return bizExceptionEnum; }}Copy the code
A global exception handling class:
@RestControllerAdvice public class GlobalHandler { private final Logger logger = LoggerFactory.getLogger(GlobalHandler.class); @ExceptionHandler(MethodArgumentNotValidException.class) public Result exceptionHandler(MethodArgumentNotValidException e) { Result result = new Result(BizExceptionEnum.INVALID_REQ_PARAM.getErrorCode(), BizExceptionEnum.INVALID_REQ_PARAM.getErrorMsg()); logger.error("req params error", e); return result; } @ExceptionHandler(BizException.class) public Result exceptionHandler(BizException e) { BizExceptionEnum exceptionEnum = e.getBizExceptionEnum(); Result result = new Result(exceptionEnum.getErrorCode(), exceptionEnum.getErrorMsg()); logger.error("business error", e); return result; } @ExceptionHandler(value = Exception.class) public Result exceptionHandler(Exception e) { Result result = new Result(BizExceptionEnum.APPLICATION_ERROR.getErrorCode(), BizExceptionEnum.APPLICATION_ERROR.getErrorMsg()); logger.error("application error", e); return result; }}Copy the code
The Result class is defined as follows:
public class Result<T> {
private Boolean success;
private Integer errorCode;
private String errorMsg;
private T data;
public Result(T data) {
this(true, null, null, data);
}
public Result(Integer errorCode, String errorMsg) {
this(false, errorCode, errorMsg, null);
}
public Result(Boolean success, Integer errorCode, String errorMsg, T data) {
this.success = success;
this.errorCode = errorCode;
this.errorMsg = errorMsg;
this.data = data;
}
// get set......
}
Copy the code
Example Controller class:
@RestController
@RequestMapping("/json/exam")
public class ExamController {
@Autowired
private IExamService examService;
@PostMapping("/getExamList")
public Result<List<GetExamListResVo>> getExamList(@Validated @RequestBody GetExamListReqVo reqVo,
@AuthenticationPrincipal UserDetails userDetails)
throws IOException {
List<GetExamListResVo> resVos = examService.getExamList(reqVo, userDetails);
Result<List<GetExamListResVo>> result = new Result(resVos);
return result;
}
}
Copy the code
The Result class is defined as follows:
public class Result<T> {
private Boolean success;
private Integer errorCode;
private String errorMsg;
private T data;
public Result(T data) {
this(true, null, null, data);
}
public Result(Integer errorCode, String errorMsg) {
this(false, errorCode, errorMsg, null);
}
public Result(Boolean success, Integer errorCode, String errorMsg, T data) {
this.success = success;
this.errorCode = errorCode;
this.errorMsg = errorMsg;
this.data = data;
}
// get set......
}
Copy the code
Example Controller class:
@RestController
@RequestMapping("/json/exam")
public class ExamController {
@Autowired
private IExamService examService;
@PostMapping("/getExamList")
public Result<List<GetExamListResVo>> getExamList(@Validated @RequestBody GetExamListReqVo reqVo,
@AuthenticationPrincipal UserDetails userDetails)
throws IOException {
List<GetExamListResVo> resVos = examService.getExamList(reqVo, userDetails);
Result<List<GetExamListResVo>> result = new Result(resVos);
return result;
}
}
Copy the code
Example Service class:
@Service public class IExamServiceImpl implements IExamService { @Autowire private ManualMicrowebsiteMapper microwebsiteMapper; @Override public List<GetExamListResVo> getExamList(GetExamListReqVo reqVo, UserDetails userDetails) throws IOException { List<MicrowebsiteExam> examEntities = microwebsiteMapper.select(reqVo.getExamType(), userDetails.getUsername()); If (examentities.isempty ()) {if (examentities.isempty ()) {if (examentities.isempty ()) {if (examentities.isempty ()) {if (examentities.isempty ()) {if (examentities.isempty ()) BizException(BizExceptionEnum.EXAM_NOT_FOUND); } // there are other kinds of exceptions in this code that throw...... List<GetExamListResVo> resVos = examEntities.stream().map(examEntity -> { GetExamListResVo resVo = new GetExamListResVo(); BeanUtils.copyProperties(examEntity, resVo); return resVo; }).collect(toList()); return resVos; }}Copy the code
Examples of C-side projects
-
In fact, the C-side project is basically the same as the above mentioned, but we are generally micro service development, so we should return a range of business exception code for each service at the beginning, so that we can know from the source of the request which system is the fault point, this is the first point
-
Second, in fact, for each Service, and the exception handling as above, but I want to say is that for the above processing Service, we should be on the inside of a business exception more exquisite and to deal with, because we just throw some we can in anticipation of some business is unusual, but some such as JSON conversion anomalies and so on, We want to deal with the outermost layer, but the most outer layer is the exception into a big exception, that is to say for C side projects, so, it should not be not enough, we should be subdivided, is as far as possible put some possible exception into our business exception, in this way, the robustness of our code will be much better, And a lot of abnormal display to the user’s copy can also be unified conversion. Let’s look at an example of a Service untying a business.
ThirdAcct ThirdAcct = null; ThirdAcct = null; try { thirdAcct = thirdAcctRelationService.getNormalThirdAcct(chId, userType, thirdUserId, payMethod, chAccountId); } catch (DataAccessException e) { throw new UIDataAccessException(e.getCode(), e.getMessage(), "fail.thirdAcct.queryfail",e); If (objectutil. isNull(thirdAcct)) {return Boolean.TRUE; } //1.2 exists, which indicates that the account is waiting to be deleted // 2. try { chAccount = chAccountRelationService.getChAccount(appId, chId, payMethod, chAccountId); } catch (DataAccessException e) {throw new UIDataAccessException(LLDB etCode(), LLDB etMessage(), "fail.chAccount.miss",e); } if (objectutil. isNull(chAccount)) {throw new UIDataAccessException("fail. ChAccount. Miss ", ", "fail.chAccount.miss"); } ChannelRelationService channelService = this.getChannelRelationService(chId); If (channelService == null) {throw new UIDataAccessException("fail.channel.unfound", Unbind (chAccount,thirdAcct) {channelservice. unbind(chAccount,thirdAcct); } catch (DataAccessException e) { throw new UIDataAccessException(e.getCode(), e.getMessage(), "fail.thirdChannel.bindFail",e); } / / 4. Unbundling, pay attention to these multiple joint components, according to the condition to unbundling, try {thirdAcctRelationService. UnbindThirdAcct (thirdAcct); } catch (DataAccessException e) { throw new UIDataAccessException(e.getCode(), e.getMessage(), "fail.dbthirdacct.bindFail",e); }Copy the code
We can see that a business may be split more child, then each child business are likely to cast a different exception, you need to put them in the different child business business into the UI abnormalities, large enough as long as your system, then unexpected exception will be very few, so your system will be more and more stable.
The end of the
Ok, small share to this today, may be a lot of friend to see will feel do not have what thing, that’s because you don’t have experienced the rigor of a C end product, if it’s just a background management, is really unnecessary, but for the products for the user, I think the stand or fall of exception handling, determines your quality of the system of this product! Good, I am small 66, three days fishing, two days drying nets!