如何寫出高質量代碼,大佬10板斧經驗分享!!!

這幾天開發遇到了很多坑,大部分坑都是自己前期沒規劃好,後期因爲業務已經開發完了,如果要進行大修改,又要回歸測試所有的功能,最後只能不了了之。入坑後出坑的代價太大了,所以想分享一些日常開發心得,也希望童鞋們不要走我的老路。好了廢話不多說,開始今天入坑血淚史介紹。

一、請使用對象參數

爲什麼方法參數最好用對象呢,核心原因就是爲了好擴展,特別是service服務,每一個方法可能都會有很多地方引用,如果方法參數發生變動,那意味着所有調用這個方法的地方,都得進行修改,這個工作量可想而知。

下面我們來舉一個例子:

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個呢?瞬間想死的心都有了。

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

如果我們用對象作爲接口的參數,就可以很大程度上,避免這個問題,就算需要添加新的判斷類型,只要在對象中新增一個字段,然後修改各自的代碼即可。

二、常量請使用枚舉:

上面的代碼有一個性別這個字段,如果我對這個字段沒有添加任何註解,大家是不是都不知道這個字段的含義,一方面是可讀性太差,另一方面因爲沒有做限制,客戶端就是隨意設置值,安全方面也有很大的隱患。

如果我們修改爲用枚舉來標識性別呢?大家來看一下代碼:

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到底是什麼性別了,直接設置對應的英文名稱即可,安全又可讀。

三、請不要讓方法喫成胖子

很多人開發的時候很喜歡,把一整個業務寫一個方法裏面,導致方法的代碼又多又長,過一段時間,自己修改都有吐血的衝動,下面我們來看看這種神級代碼。

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;
    }
}

就比如上面的例子,如果財富的計算方式很複雜的化,所有的計算邏輯全部寫在一個方法裏面,就會顯得方法很臃腫,代碼可讀性差不說,如果沒有相關的註解,修改都不知道從何入手。我們將上面的計算公式拆分爲一個個函數,來看看會不會有什麼改變。

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嵌套,跳來跳去,這也是爲什麼祖傳代碼幾乎修改不了的一個很大原因,比如上述財富值計算是各個維護分開的,如果是各個維度相互關聯的呢,直接實現會變成什麼樣子呢?

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中直接添加,例如:

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

然後相關需求一來,又要加一種類型,就會導致這個服務越來越大,大到最後你不可維護,變成傳說中的祖傳代碼,如果是如上這種情況,博主建議大家可以新建一個服務類,讓各個服務類的職責單一(單一指責原則)。

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 向模板渲染引擎層傳輸的對象。

接口的請求參數要準確,前端不需要傳的字段,最好不要暴露出去,這樣也會減少雙方的溝通成本,而且後續升級接口的時候,也可以確定參數的各自含義。

@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對象,這樣就會對剩餘的參數產生困擾。

@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值。

@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(接口的業務數據),我們將上面的接口修改一下。

@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(可以根據自己需求添加),例如:

/**
 * 基礎異常類
 * 用途:用於在處理業務時,向框架拋出異常,框架將該異常作爲錯誤信息進行輸出。<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了,但是到線上的時候可沒辦法進行錯誤調試,甚至有些錯誤是瞬間性的,下一刻你就復現不出來了,所以如果沒有日誌記錄這些錯誤信息,那就相當於蒙着眼睛過河一樣,岌岌可危。

總結:

日常開發經驗就分享到這邊了,當然還有很多很多的場景博主沒有說,這得靠童鞋們平時的積累了。博客的爬坑歷程就到這邊了,對上述有疑問或者想分享交流的童靴,歡迎隨時@博主哦~

想要更多幹貨、技術猛料的孩子,快點拿起手機掃碼關注我,我在這裏等你哦~

林老師帶你學編程https://wolzq.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章