如何写出高质量代码,大佬10板斧经验分享!!!

2020-06-16 17:43:12 浏览数 (2)

这几天开发遇到了很多坑,大部分坑都是自己前期没规划好,后期因为业务已经开发完了,如果要进行大修改,又要回归测试所有的功能,最后只能不了了之。入坑后出坑的代价太大了,所以想分享一些日常开发心得,也希望童鞋们不要走我的老路。好了废话不多说,开始今天入坑血泪史介绍。

一、请使用对象参数

为什么方法参数最好用对象呢,核心原因就是为了好扩展,特别是service服务,每一个方法可能都会有很多地方引用,如果方法参数发生变动,那意味着所有调用这个方法的地方,都得进行修改,这个工作量可想而知。

下面我们来举一个例子:

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(int age) {
        if (age < 20) {
            return 5;
        } else {
            return 10;
        }
    }
}

public class Child {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        return personService.getTreasureIndicator(10);
    }
}

public class Old {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        return personService.getTreasureIndicator(50);
    }
}

public class Test {
    public static void main(String[] args) {
        Child child = new Child();
        Old old = new Old();
        System.out.println("child:"   child.getTreasureIndicator());
        System.out.println("old:"   old.getTreasureIndicator());
    }
}

child:5
old:10

咋一看好像没什么问题,但是后续需求如果修改成,小孩指标计算不变,但是老人的指标需要加上性别这个字段呢?理想状态是只要修改老人的请求参数和服务类就可以了,但是现在因为只有一个参数,如果加上另外一个参数,就意味着所有的引用到这个方法的地方都需要修改。这还是两个,要是10个呢?瞬间想死的心都有了。

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(PersonDto personDto) {
        if (personDto.getAge() >= 20 && personDto.getSex()==1) {
            return 8;
        } else if(personDto.getAge() >= 20 && personDto.getSex()==2){
            return 10;
        }else {
            return 5;
        }
    }
}

public class Child {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(10);
        return personService.getTreasureIndicator(personDto);
    }
}

public class Old {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(50);
        personDto.setSex(1);
        return personService.getTreasureIndicator(personDto);
    }
}

public class Test {
    public static void main(String[] args) {
        Child child = new Child();
        Old old = new Old();
        System.out.println("child:"   child.getTreasureIndicator());
        System.out.println("old:"   old.getTreasureIndicator());
    }
}
child:5
old:8

如果我们用对象作为接口的参数,就可以很大程度上,避免这个问题,就算需要添加新的判断类型,只要在对象中新增一个字段,然后修改各自的代码即可。

二、常量请使用枚举:

上面的代码有一个性别这个字段,如果我对这个字段没有添加任何注解,大家是不是都不知道这个字段的含义,一方面是可读性太差,另一方面因为没有做限制,客户端就是随意设置值,安全方面也有很大的隐患。

如果我们修改为用枚举来标识性别呢?大家来看一下代码:

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(PersonDto personDto) {
        if (personDto.getAge() >= 20 && personDto.getSex()==SexEnum.SEX_GIRL.getSex()) {
            return 8;
        } else if(personDto.getAge() >= 20 && personDto.getSex()==SexEnum.SEX_BOY.getSex()){
            return 10;
        }else {
            return 5;
        }
    }
}

public class Old {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(50);
        personDto.setSex(SexEnum.SEX_GIRL.getSex());
        return personService.getTreasureIndicator(personDto);
    }
}

public enum SexEnum {
    SEX_GIRL(1), SEX_BOY(2);

    /**
     * 性别
     */
    private int sex;

    SexEnum(int sex) {
        this.sex = sex;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }
}

从枚举的英文单词中就可以马上读懂性别是什么,而且设置值的时候也不需要判断1、2到底是什么性别了,直接设置对应的英文名称即可,安全又可读。

三、请不要让方法吃成胖子

很多人开发的时候很喜欢,把一整个业务写一个方法里面,导致方法的代码又多又长,过一段时间,自己修改都有吐血的冲动,下面我们来看看这种神级代码。

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(PersonDto personDto) {
        int result = 0;
        // 计算年龄得分
        if (personDto.getAge() < 20) {
            result  = 5;
        } else if (personDto.getAge() >= 20) {
            result  = 10;
        }
        // 计算性别得分
        if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
            result  = 5;
        } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
            result  = 10;
        }
        // 计算家庭得分
        if (personDto.getFamilyMembers() < 5) {
            result  = 5;
        } else if (personDto.getFamilyMembers() >= 5) {
            result  = 10;
        }
        // 计算颜值得分
        if (personDto.getFaceScore() < 5) {
            result  = 5;
        } else if (personDto.getFaceScore() >= 5) {
            result  = 10;
        }
        // 计算身高得分
        if (personDto.getHeight() < 170) {
            result  = 5;
        } else if (personDto.getHeight() >= 170) {
            result  = 10;
        }
        return result;
    }
}

就比如上面的例子,如果财富的计算方式很复杂的化,所有的计算逻辑全部写在一个方法里面,就会显得方法很臃肿,代码可读性差不说,如果没有相关的注解,修改都不知道从何入手。我们将上面的计算公式拆分为一个个函数,来看看会不会有什么改变。

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(PersonDto personDto) {
        int result = 0;
        result  = getAgeScore(personDto);
        result  = getSexScore(personDto);
        result  = getFamilyMembersScore(personDto);
        result  = getFaceScore(personDto);
        result  = getHeightScore(personDto);
        return result;
    }

    private int getAgeScore(PersonDto personDto){
        int result = 0;
        if (personDto.getAge() < 20) {
            result  = 5;
        } else if (personDto.getAge() >= 20) {
            result  = 10;
        }
        return result;
    }

    private int getSexScore(PersonDto personDto){
        int result = 0;
        if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
            result  = 5;
        } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
            result  = 10;
        }
        return result;
    }

    private int getFamilyMembersScore(PersonDto personDto){
        int result = 0;
        if (personDto.getFamilyMembers() < 5) {
            result  = 5;
        } else if (personDto.getFamilyMembers() >= 5) {
            result  = 10;
        }
        return result;
    }

    private int getFaceScore(PersonDto personDto){
        int result = 0;
        if (personDto.getFaceScore() < 5) {
            result  = 5;
        } else if (personDto.getFaceScore() >= 5) {
            result  = 10;
        }
        return result;
    }

    private int getHeightScore(PersonDto personDto){
        int result = 0;
        if (personDto.getHeight() < 170) {
            result  = 5;
        } else if (personDto.getHeight() >= 170) {
            result  = 10;
        }
        return result;
    }
}

如果将各个计算方式细分之后,就算我们不添加任何的注解,也可以明显看出计算公式是由什么组成的,每个公式的计算细节是什么。代码的可读性和可维护性大大增强了。

四、请不要一层层嵌套if-else

祖传老代码中,很多都有非常多的if-else嵌套,跳来跳去,这也是为什么祖传代码几乎修改不了的一个很大原因,比如上述财富值计算是各个维护分开的,如果是各个维度相互关联的呢,直接实现会变成什么样子呢?

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(PersonDto personDto) {
        int result = 0;
        if (personDto.getAge() < 20) {
            if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
                if (personDto.getFamilyMembers() < 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    }
                } else if (personDto.getFamilyMembers() >= 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    }
                }
            } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
                if (personDto.getFamilyMembers() < 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getFaceScore() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getFaceScore() >= 170) {
                            result  = 10;
                        }
                    }
                } else if (personDto.getFamilyMembers() >= 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    }
                }
            }
        } else if (personDto.getAge() >= 20) {
            if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
                if (personDto.getFamilyMembers() < 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    }
                } else if (personDto.getFamilyMembers() >= 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    }
                }
            } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
                if (personDto.getFamilyMembers() < 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            if (personDto.getHeight() < 170) {
                                result  = 5;
                            } else if (personDto.getHeight() >= 170) {
                                result  = 10;
                            }
                        } else if (personDto.getFaceScore() >= 170) {
                            if (personDto.getHeight() < 170) {
                                result  = 5;
                            } else if (personDto.getHeight() >= 170) {
                                result  = 10;
                            }
                        }
                    }
                } else if (personDto.getFamilyMembers() >= 5) {
                    if (personDto.getFaceScore() < 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    } else if (personDto.getFaceScore() >= 5) {
                        if (personDto.getHeight() < 170) {
                            result  = 5;
                        } else if (personDto.getHeight() >= 170) {
                            result  = 10;
                        }
                    }
                }
            }
        }
        return result;
    }
}

看到这样的代码就问你绝望不,一般来说,我们的if-else结构最好不要超过三层,因为如果超过三层的话,代码可读性已经变动特别差了。if-else的优化,网上有很多方法,博主这边就不多做介绍了,最有效的就是将if-else进行拆分,由各个函数自己去实现,这样就可以最大程度避免多层嵌套了。

五、请不要在一个服务中做太多事情

博主遇到过很多之前定义了一个服务类,然后之后和这个服务类相关的业务,就全部写到这个服务类中,最后导致服务类代码超过3000行,改也改不动,因为引用的地方实在是太多了,根本没办法知道这个服务类到底做了哪些事情,跟黑盒一样。就比如我们上面的服务类,如果新加一个健康指标计算的方法,我相信很多人会直接在PersonService中直接添加,例如:

代码语言:javascript复制
public class PersonService {
    public int getTreasureIndicator(PersonDto personDto) {
        int result = 0;
        result  = getAgeScore(personDto);
        result  = getSexScore(personDto);
        result  = getFamilyMembersScore(personDto);
        result  = getFaceScore(personDto);
        result  = getHeightScore(personDto);
        return result;
    }

    public int getHealthIndicator(PersonDto personDto) {
        int result = 0;
        result  = getAgeScore(personDto);
        result  = getSexScore(personDto);
        result  = getFamilyMembersScore(personDto);
        result  = getFaceScore(personDto);
        result  = getHeightScore(personDto);
        return result;
    }

    private int getAgeScore(PersonDto personDto){
        int result = 0;
        if (personDto.getAge() < 20) {
            result  = 5;
        } else if (personDto.getAge() >= 20) {
            result  = 10;
        }
        return result;
    }

    private int getSexScore(PersonDto personDto){
        int result = 0;
        if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
            result  = 5;
        } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
            result  = 10;
        }
        return result;
    }

    private int getFamilyMembersScore(PersonDto personDto){
        int result = 0;
        if (personDto.getFamilyMembers() < 5) {
            result  = 5;
        } else if (personDto.getFamilyMembers() >= 5) {
            result  = 10;
        }
        return result;
    }

    private int getFaceScore(PersonDto personDto){
        int result = 0;
        if (personDto.getFaceScore() < 5) {
            result  = 5;
        } else if (personDto.getFaceScore() >= 5) {
            result  = 10;
        }
        return result;
    }

    private int getHeightScore(PersonDto personDto){
        int result = 0;
        if (personDto.getHeight() < 170) {
            result  = 5;
        } else if (personDto.getHeight() >= 170) {
            result  = 10;
        }
        return result;
    }
}

public class Child {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(10);
        return personService.getTreasureIndicator(personDto);
    }

    public int getHealthIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(10);
        return personService.getHealthIndicator(personDto);
    }
}

public class Old {
    public int getTreasureIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(50);
        personDto.setSex(SexEnum.SEX_GIRL.getSex());
        return personService.getTreasureIndicator(personDto);
    }

    public int getHealthIndicator() {
        PersonService personService = new PersonService();
        PersonDto personDto = new PersonDto();
        personDto.setAge(10);
        return personService.getHealthIndicator(personDto);
    }
}

public class Test {
    public static void main(String[] args) {
        Child child = new Child();
        Old old = new Old();
        System.out.println("child-treasure:"   child.getTreasureIndicator());
        System.out.println("child-health:"   child.getHealthIndicator());
        System.out.println("old-treasure:"   old.getTreasureIndicator());
        System.out.println("old-health:"   old.getHealthIndicator());
    }
}
child-treasure:20
child-health:20
old-treasure:30
old-health:20

然后相关需求一来,又要加一种类型,就会导致这个服务越来越大,大到最后你不可维护,变成传说中的祖传代码,如果是如上这种情况,博主建议大家可以新建一个服务类,让各个服务类的职责单一(单一指责原则)。

代码语言:javascript复制
public class PersonService {
    protected int getAgeScore(PersonDto personDto){
        int result = 0;
        if (personDto.getAge() < 20) {
            result  = 5;
        } else if (personDto.getAge() >= 20) {
            result  = 10;
        }
        return result;
    }

    protected int getSexScore(PersonDto personDto){
        int result = 0;
        if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
            result  = 5;
        } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
            result  = 10;
        }
        return result;
    }

    protected int getFamilyMembersScore(PersonDto personDto){
        int result = 0;
        if (personDto.getFamilyMembers() < 5) {
            result  = 5;
        } else if (personDto.getFamilyMembers() >= 5) {
            result  = 10;
        }
        return result;
    }

    protected int getFaceScore(PersonDto personDto){
        int result = 0;
        if (personDto.getFaceScore() < 5) {
            result  = 5;
        } else if (personDto.getFaceScore() >= 5) {
            result  = 10;
        }
        return result;
    }

    protected int getHeightScore(PersonDto personDto){
        int result = 0;
        if (personDto.getHeight() < 170) {
            result  = 5;
        } else if (personDto.getHeight() >= 170) {
            result  = 10;
        }
        return result;
    }
}

public class PersonHealthService extends PersonService{
    public int getHealthIndicator(PersonDto personDto) {
        int result = 0;
        result  = getAgeScore(personDto);
        result  = getSexScore(personDto);
        result  = getFamilyMembersScore(personDto);
        result  = getFaceScore(personDto);
        result  = getHeightScore(personDto);
        return result;
    }
}

public class PersonTreasureService extends PersonService{
    public int getTreasureIndicator(PersonDto personDto) {
        int result = 0;
        result  = getAgeScore(personDto);
        result  = getSexScore(personDto);
        result  = getFamilyMembersScore(personDto);
        result  = getFaceScore(personDto);
        result  = getHeightScore(personDto);
        return result;
    }
}

因为两个服务有很多的共性代码,所以直接抽出来作为他们的父类,所以也就有上面的代码了,这样以后有新的业务进来,只需要创建对应的服务类就可以了(开闭原则)。

六、请规范好请求参数

在写接口的时候,很多人会遇到该用基础类型的字段呢(int、String之类)还是使用对象来接收呢,如果用对象来接收,大家就会倾向于,后续相关的接口还是直接用这个对象来接收,这就会导致对象的字段越来越多,最后造成前端每次都会过来问,这个接口应该传哪些字段。。。

分层领域模型规约:

  1. DO(Data Object):与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。(Entity)
  2. DTO(Data Transfer Object):数据传输对象,Service 和 Manager 向外传输的对象。
  3. BO(Business Object):业务对象。可以由 Service 层输出的封装业务逻辑的对象。
  4. QUERY:数据查询对象,各层接收上层的查询请求。注:超过 2 个参数的查询封装,禁止 使用 Map 类来传输。
  5. VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。

接口的请求参数要准确,前端不需要传的字段,最好不要暴露出去,这样也会减少双方的沟通成本,而且后续升级接口的时候,也可以确定参数的各自含义。

代码语言:javascript复制
@Controller
@RequestMapping("/api/person")
@Slf4j
public class PersonController {

    @ResponseBody
    @PostMapping("/getChildHealthIndicator")
    public int getChildHealthIndicator(@RequestBody PersonDto personDto) {
        Child child = new Child();
        return child.getHealthIndicator(personDto.getAge());
    }
}

就比如getChildHealthIndicator接口只需要age值,但是前端那边看到却是personDto对象,这样就会对剩余的参数产生困扰。

代码语言:javascript复制
@Controller
@RequestMapping("/api/person")
@Slf4j
public class PersonController {

    @ResponseBody
    @PostMapping("/getChildHealthIndicator")
    public int getChildHealthIndicator(@RequestBody ChildHealthIndicatorQuery childHealthIndicatorQuery) {
        Child child = new Child();
        return child.getHealthIndicator(childHealthIndicatorQuery.getAge());
    }
}

@Data
public class ChildHealthIndicatorQuery {
    private int age;
}

如果用ChildHealthIndicatorQuery来代替PersonDto,这样前端看到的就只有age这个字段,可以无歧义的进行传参。当然正常开发过程中,肯定不会设计的这么细,不然会产生大量的pojo对象,要根据实际项目来设计。

七、entity中请不要做参数校验

我以前遇到同事,直接在entity(数据库表映射类)里面做判断,然后另外一个同事,因为数据库新增了字段,所以又重新生成了一遍entity类(mybatis插件生成),写完业务代码后发布,最后结果可想而知。

对于entity类,是绝对禁止任何层面的判断修改的,因为这个类随时都有可能被覆盖。

八、http返回码请不要直接返回一个字段

很多童鞋刚开始写代码的时候,很喜欢接口业务需要返回什么内容,就直接返回数据,例如上面的案例就是直接返回一个int值。

代码语言:javascript复制
@Controller
@RequestMapping("/api/person")
@Slf4j
public class PersonController {

    @ResponseBody
    @PostMapping("/getChildHealthIndicator")
    public int getChildHealthIndicator(@RequestBody ChildHealthIndicatorQuery childHealthIndicatorQuery) {
        Child child = new Child();
        return child.getHealthIndicator(childHealthIndicatorQuery.getAge());
    }
}

但是大家要知道,任何的接口都有出问题的可能性,而且问题还不止一种,可能是五花八门,前端可能需要根据不同的错误进行相应的提示,所以直接返回一个字段数据肯定是不合理的。一般来说,至少需要返回三个字段:code(状态码)、msg(状态码对应的说明)、data(接口的业务数据),我们将上面的接口修改一下。

代码语言:javascript复制
@Controller
@RequestMapping("/api/person")
@Slf4j
public class PersonController {

    @ResponseBody
    @PostMapping("/getChildHealthIndicator")
    public CustResponse getChildHealthIndicator(@RequestBody ChildHealthIndicatorQuery childHealthIndicatorQuery) {
        Child child = new Child();
        CustResponse custResponse = new CustResponse();
        try{
            int result = child.getHealthIndicator(childHealthIndicatorQuery.getAge());
            custResponse.setCode(200);
            custResponse.setMsg("success");
            custResponse.setDetails(result);
        }catch (Exception e){
            custResponse.setCode(500);
            custResponse.setMsg(e.getMessage());
        }
        return custResponse;
    }
}

@Data
@ApiModel
public class CustResponse {

	/**
	 * 200 成功
	 * 500 失败
	 */
	@ApiModelProperty(value = "状态码,200 = '成功',500 = '失败'")
	private Integer code;
	@ApiModelProperty(value = "返回消息")
	private String msg;
	@ApiModelProperty(value = "返回实体")
	private Object details;

	public CustResponse() {
		super();
	}

	/**
	 * @param code
	 * @param msg
	 */
	public CustResponse(Integer code, String msg) {
		super();
		this.code = code;
		this.msg = msg;
	}

	/**
	 * @param code
	 * @param details
	 */
	public CustResponse(Integer code, Object details) {
		super();
		this.code = code;
		this.details = details;
	}
}

九、请定义好异常的状态码

很多童靴抛异常,很喜欢直接抛出RuntimeException异常,然后就一串异常信息,想看这个异常是属于哪一个服务,哪一块业务,核心参数等,都没有。。。排查问题难度直线上升。

所以定义异常的时候一般需要定义code msg(可以根据自己需求添加),例如:

代码语言:javascript复制
/**
 * 基础异常类
 * 用途:用于在处理业务时,向框架抛出异常,框架将该异常作为错误信息进行输出。<br>
 * 使用场景:比如在深层业务代码判断参数无正确,就可以直接抛出该异常。<br>
 * <pre>
 * code rule:{2}{2}{4}
 *            |  |  |
 *           sys |  |
 *            module|
 *                error
 * 如:[10020001]前四位数为系统 模块编号,后4位为错误代码
 *
 * @Author: linzhiqiang
 */
@Data
public class BaseException extends RuntimeException implements Serializable {
    private static final long serialVersionUID = -5196111058043675557L;

    /**
     * 参数不能为空
     **/
    public static final BaseException PARAMS_NOT_NULL = new BaseException(10000000, "参数{0}不能为空");
    /**
     * 参数非法
     **/
    public static final BaseException PARAMS_IS_ILLICIT = new BaseException(10000001, "参数{0}非法");

    private Integer code;
    private String msg;

    public BaseException() {
        super();
    }

    public BaseException(String msg) {
        super(msg);
        this.msg = msg == null ? "" : msg;
    }

    public BaseException(Integer code, String msg) {
        super(msg);
        this.code = code;
        this.msg = msg == null ? "" : msg;
    }

    public BaseException(Integer code, String msg, Integer userId) {
        super(msg);
        this.code = code;
        msg = msg == null ? "" : msg;
        this.msg = userId   ":"   msg;
    }

    /**
     * 格式化消息
     *
     * @param args
     */
    public BaseException format(Object... args) {
        return new BaseException(this.code, MessageFormat.format(this.msg, args));
    }
}

public int getHealthIndicator(int age) {
    if (age < 0) {
        BaseException baseException = new BaseException(01010001, "年龄不能小于0");
        throw baseException;
    }
    PersonHealthService personService = new PersonHealthService();
    PersonDto personDto = new PersonDto();
    personDto.setAge(age);
    return personService.getHealthIndicator(personDto);
}

通过这种方式抛出的异常,我们就可以很明显的找到这个异常对应的服务、模块、错误内容,加快我们排查效率。

十、不要吝啬,请多打点错误日志

很多童靴写代码没有打印日志的习惯,可能很多时候因为是本地开发,出问题的时候直接调试一下就ko bug了,但是到线上的时候可没办法进行错误调试,甚至有些错误是瞬间性的,下一刻你就复现不出来了,所以如果没有日志记录这些错误信息,那就相当于蒙着眼睛过河一样,岌岌可危。

总结:

日常开发经验就分享到这边了,当然还有很多很多的场景博主没有说,这得靠童鞋们平时的积累了。博客的爬坑历程就到这边了,对上述有疑问或者想分享交流的童靴,欢迎随时@博主哦~

0 人点赞