Exceptions: Role, Optimized Development, and Assertions

Keywords: Java

0 Summary

Exceptionally reasonable application takes up a large proportion in the daily development, which can improve the development efficiency. The following are mainly divided into why there are exceptions, the role of exceptions and how to use them rationally.

1 Origin

Early development languages had no abnormal concepts, such as C.C has a return, and the programmer determines if execution is successful by returning a value of 1 or 0
The concept of exceptions was introduced in java, but many of the code actually uses return values to make judgments
It's like drilling wood for fire in modern society

2 Two roles of anomaly

2.1 Force a programmer not to ignore a situation

In C, we use return to return whether it was successful or not.But in fact, if his return value is 0 (error) and the developer doesn't handle him, the code will run.
Exceptions in java must try-catch or compile will fail.

2.2 Optimize development and improve development efficiency

The following are common ways to handle non-exception style s

CarService
public int update(Car car){
  return carDao.update(car);
}

This is a common way to write a service layer, telling the upper layer if it was successful by returning the number of updates, as the upper layer code would write

CarController:
public String update(Car car){
  Map<String,String> rtnMap = new HashMap<String, String>();
  try{
    int i = carServce.update(car);  
    if(i == 0){  
      rtnMap.put("code", "200"); 
      rtnMap.put("msg", "Update Successful");
    } else{  
      rtnMap.put("code", "500"); 
      rtnMap.put("msg", "Update failed");
    }
  }catch(Exception){
      rtnMap.put("code", "200"); 
      rtnMap.put("msg", "Update failed");
  }
}

There are two problems with this code

  • User can see only one update failure Why failed, user can not see
  • If the service is invoked in more than one place, the code handled by this if-else coat Exception will appear in all places where the interface is called, and if the rules change, all calls to the interface will change

For the first question, there are places where the following modifications are made

CarService:
public Map<String, String> update(Car car){
  Map<String, String> rtnMap = new HashMap<String, String>();
  if(car.getId() == null || "".equals(car.getId()) ){
    rtnMap.put("code" , "500");
    rtnMap.put("msg", "id Cannot be empty");
    return rtnMap;
  }
  if(carDao.update(car) == 0 ){
    rtnMap.put("code" , "500");
    rtnMap.put("msg", "Update failed");
    return rtnMap;
  }else{
    rtnMap.put("code" , "200");  
    rtnMap.put("msg", "Update Successful");  
    return rtnMap;
  }
}

Now it's obvious that a lot of code is writing return information instead of business logic, and if this is a more rigorous way to check entry, his code might look like this

CarService:
public Map<String, String> update(Car car){
  Map<String, String> rtnMap = new HashMap<String, String>();
  if(car.getId() == null || "".equals(car.getId()) ){
    rtnMap.put("code" , "500");
    rtnMap.put("msg", "id Cannot be empty");
    return rtnMap;
  }
  if(car.getCarNo() == null || "".equals(car.getCarNo()) ){
    rtnMap.put("code" , "500");
    rtnMap.put("msg", "License plate number cannot be empty");
    return rtnMap;
  }
  if(car.getUser() == null || "".equals(car.getUser()) ){
    rtnMap.put("code" , "500");
    rtnMap.put("msg", "Car owner information cannot be empty");
    return rtnMap;
  }
  // Wait for other checks
  // ...

  // Here's some business logic
  // ...
  if(carDao.update(car) == 0 ){
    rtnMap.put("code" , "500");
    rtnMap.put("msg", "Update failed");
    return rtnMap;
  }else{
    rtnMap.put("code" , "200");  
    rtnMap.put("msg", "Update Successful");  
    return rtnMap;
  }
}
  • If this is called by other code, rtnMap will be judged by all callers. If it is not judged, there may be problems with the subsequent process. If it is judged, he will process rtnMap and return a map to his caller.
  • There is too much return information in the code to read and maintain.

If you switch to an exception, this is the code below

CarService:
public void update(Car car) throws ServiceException{
  if(car.getId() == null || "".equals(car.getId()) ){
    throw new ServiceException("id Cannot be empty");
  }
  if(car.getCarNo() == null || "".equals(car.getCarNo()) ){
    throw new ServiceException("License plate number cannot be empty");
  }
  if(car.getUser() == null || "".equals(car.getUser()) ){
    throw new ServiceException("Car owner information cannot be empty");
  }
  // Wait for other checks
  // ...

  // Here's some business logic
  // ...
  if(carDao.update(car) == 0 ){
    throw new ServiceException("Update failed");
  }
}

Code is compressed by about two-thirds, if combined with assertions
Create a new assertion class

public class ServiceAssertUtil{
  public static void hasLength(String str, String msg) throws ServiceException(){
    if(null == str || "".equals(str.trim()) ){
      throw new ServiceException(msg);
    }
  }

  public static void isTrue(Boolean boolean, String msg) throws ServiceException(){
    if(!boolean){
      throw new ServiceException(msg);
    }
  }
}

Code further optimization

CarService:
public void update(Car car) throws ServiceException{
  ServiceAssertUtil.hasLength(car.getId(), "id Cannot be empty");
  ServiceAssertUtil.hasLength(car.getCarNo(), "License plate number cannot be empty");
  ServiceAssertUtil.hasLength(car.getCarUser(), "Car owner information cannot be empty");
  // Wait for other checks
  // ...

  // Here's some business logic
  // ...
  ServiceAssertUtil.isTrue(carDao.update(car)==1, "Update failed");
}

Finally, the following figure is simplified. In addition to this part, his caller's code is omitted. No more examples are given here.

2.3 Effect

Optimized and optimized code do the same thing, but the amount of maintenance and code and readability are different

If the caller is a Service layer, no exception needs to be handled, just throw it up
If it's the Controller layer, try-catch judges ServiceException and Exception separately

3 Summary

Processing and returning of methods play an important role in daily development. Rationally optimizing this part of code habits can help to improve efficiency and reduce workload.

Published an original article with 10% approval and 50,000 visits+
Private letter follow

Posted by scottshane on Wed, 04 Mar 2020 18:09:40 -0800