RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Java方法設(shè)計(jì)原則與實(shí)踐:從Effective Java到團(tuán)隊(duì)案例

京東云 ? 來(lái)源:京東物流 ? 作者:京東物流 ? 2024-11-01 15:24 ? 次閱讀

作者:京東物流 京東物流

背景

本文通過(guò)閱讀《Effective Java》、《Clean Code》、《京東JAVA代碼規(guī)范》等代碼質(zhì)量書籍,結(jié)合團(tuán)隊(duì)日常代碼實(shí)踐案例進(jìn)行整理,拋磚引玉、分享一些在編寫高質(zhì)量代碼方面的見解和經(jīng)驗(yàn)。這些書籍提供了豐富的理論知識(shí),而團(tuán)隊(duì)的實(shí)際案例則展示了這些原則在實(shí)際開發(fā)中的應(yīng)用。希望通過(guò)這篇文章,能夠幫助大家更好地理解和運(yùn)用這些編程最佳實(shí)踐,提高代碼質(zhì)量和開發(fā)效率。

什么是一個(gè)好的方法

在 Java 中,方法是類的一部分,定義了類的行為。方法通常包含方法頭和方法體。方法頭包括訪問修飾符、返回類型、方法名和參數(shù)列表,而方法體包含實(shí)現(xiàn)方法功能的代碼。

方法的基本結(jié)構(gòu) [訪問修飾符] [返回類型] [方法名]([參數(shù)列表]) { // 方法體 // 實(shí)現(xiàn)方法功能的代碼 }

如果一個(gè)方法在滿足業(yè)務(wù)需求本身的基礎(chǔ)上,職責(zé)單一,清晰明了,重點(diǎn)是團(tuán)隊(duì)其他成員可以簡(jiǎn)單看懂及維護(hù),這就是一個(gè)好的方法。如果只有自己看得懂,其他人看不太懂,則不是一個(gè)好的方法。具體原則細(xì)節(jié)從以下【入?yún)ⅰ俊痉椒w】【出參】維度詳細(xì)描述

一、入?yún)?/h2>

1)入?yún)⒉灰?/h2>

理想情況下,方法的參數(shù)應(yīng)盡量少。最佳情況是沒有參數(shù),其次是一個(gè)參數(shù),再次是兩個(gè)或三個(gè)參數(shù),盡量避免超過(guò)四個(gè)參數(shù)。參數(shù)越多,方法通常越復(fù)雜。從測(cè)試的角度來(lái)看,編寫各種參數(shù)組合的單元測(cè)試場(chǎng)景也會(huì)變得復(fù)雜。

設(shè)定四個(gè)或更少的參數(shù),因?yàn)榇蠖鄶?shù)程序員記不住更長(zhǎng)的參數(shù)列表。同類型的參數(shù)尤其有害,如果不小心弄反了參數(shù)的順序,程序可以正常編譯和運(yùn)行,但結(jié)果可能不正確,這極易導(dǎo)致錯(cuò)誤。

如果方法確實(shí)需要多個(gè)參數(shù),這通常意味著這些參數(shù)應(yīng)該封裝為一個(gè)類,通過(guò)創(chuàng)建參數(shù)對(duì)象來(lái)減少參數(shù)的數(shù)量。

?錯(cuò)誤案例:重量/體積 同類型參數(shù)順序錯(cuò)誤導(dǎo)致問題

// 錯(cuò)誤的方法定義,參數(shù)過(guò)多且容易混淆
public void calculateShippingCost(double weight, double volume, double length,
                             double width, double height, String destination) {
    // 假設(shè)這里有計(jì)算運(yùn)費(fèi)的邏輯
}

// 這里將重量和體積的順序弄反了
service.calculateShippingCost(30.0, 50.0, 10.0, 5.0, 3.0, "New York");
// 實(shí)際上應(yīng)該是:
service.calculateShippingCost(50.0, 30.0, 10.0, 5.0, 3.0, "New York");

?正確案例:在這個(gè)示例中,由于重量和體積的順序弄反,計(jì)算出來(lái)的運(yùn)費(fèi)會(huì)有誤。為了避免這種錯(cuò)誤,可以將這些參數(shù)封裝成一個(gè)類:

public class ShippingDetails {
    private double weight;
    private double volume;
    private double length;
    private double width;
    private double height;
    private String destination;
    // 構(gòu)造方法、getter和setter省略
}
// 使用參數(shù)對(duì)象來(lái)簡(jiǎn)化方法簽名
public void calculateShippingCost(ShippingDetails details) {
    // 假設(shè)這里有計(jì)算運(yùn)費(fèi)的邏輯
}

通過(guò)將參數(shù)封裝成一個(gè)類,可以有效減少方法的參數(shù)數(shù)量,避免參數(shù)順序錯(cuò)誤的問題,提高代碼的可讀性和可維護(hù)性。

?

2)謹(jǐn)慎使用可變參數(shù)

可變參數(shù)數(shù)量,它接受0個(gè)或者N個(gè)指定類型的參數(shù)??勺儏?shù)的原理是根據(jù)調(diào)用位置傳入的參數(shù)數(shù)量,先創(chuàng)建一個(gè)數(shù)組,然后將參數(shù)放入這個(gè)數(shù)組中,最后將數(shù)值傳遞給該方法。

?

注意:在對(duì)性能要求很高的情況下,使用可變參數(shù)要特別小心,每次調(diào)用可變參數(shù)方法都會(huì)導(dǎo)致一次數(shù)組的分配和初始化。

?錯(cuò)誤案例:循環(huán)中調(diào)用可變參數(shù)方法

public class Logger {
    // 可變參數(shù)方法
    public void log(String level, String... messages) {
        StringBuilder sb = new StringBuilder();
        sb.append(level).append(": ");
        for (String message : messages) {
            sb.append(message).append(" ");
        }
        System.out.println(sb.toString());
    }
}

// 模擬高頻調(diào)用
for (int i = 0; i < 1000000; i++) {
    logger.log("INFO", "Message", "number", String.valueOf(i));
}

在這個(gè)案例中,log方法每次調(diào)用都會(huì)創(chuàng)建一個(gè)新的數(shù)組來(lái)保存可變參數(shù)messages。在高頻調(diào)用的場(chǎng)景下,這種數(shù)組分配和初始化的開銷會(huì)顯著影響性能。

?

?優(yōu)化案例:避免可變參數(shù)帶來(lái)的性能開銷 我們使用了List來(lái)傳遞日志消息。雖然在每次調(diào)用時(shí)仍然會(huì)創(chuàng)建一個(gè)List對(duì)象,但相比于每次創(chuàng)建一個(gè)數(shù)組,這種方式的性能開銷更小,特別是在高頻調(diào)用的場(chǎng)景下。

public class Logger {
  // 使用List代替可變參數(shù)
    public void log(String level, List messages) {
        StringBuilder sb = new StringBuilder();
        sb.append(level).append(": ");
        for (String message : messages) {
            sb.append(message).append(" ");
        }
        System.out.println(sb.toString());
    }
}

// 模擬高頻調(diào)用
for (int i = 0; i < 1000000; i++) {
    logger.log("INFO", List.of("Message", "number", String.valueOf(i)));
}

?進(jìn)一步優(yōu)化:使用StringBuilder直接拼接 在這種情況下,我們完全避免了數(shù)組或集合的創(chuàng)建,直接通過(guò)StringBuilder拼接字符串,從而最大限度地減少了性能開銷。

public class Logger {
   // 使用StringBuilder直接拼接
    public void log(String level, String message1, String message2, String message3) {
        StringBuilder sb = new StringBuilder();
        sb.append(level).append(": ")
          .append(message1).append(" ")
          .append(message2).append(" ")
          .append(message3).append(" ");
        System.out.println(sb.toString());
    }
}

// 模擬高頻調(diào)用
for (int i = 0; i < 1000000; i++) {
    logger.log("INFO", "Message", "number", String.valueOf(i));
}

?

如果無(wú)法承受上面的性能開銷,但又需要可變參數(shù)的便利性,可以有一種兼容的做法,假設(shè)方法95%的調(diào)用參數(shù)不超過(guò)3個(gè),那么我們可以聲明該方法的5個(gè)重載版本,分別包含(0,1,2,3)個(gè)參數(shù)和一個(gè)(3,可變參數(shù)),這樣只有最后一個(gè)方法才需要付出創(chuàng)建數(shù)組的開銷,而這只占用5%的調(diào)用。

?案例:org.slf4j.Logger 每個(gè)日志級(jí)別都有多個(gè)重載的方法,支持不同數(shù)量的參數(shù),通過(guò)這些方法,SLF4J 提供了靈活且高效的日志記錄接口,可以適應(yīng)各種不同的日志記錄需求。

package org.slf4j;
public interface Logger {
    public boolean isInfoEnabled();
    public void info(String msg);
    public void info(String format, Object arg);
    public void info(String format, Object arg1, Object arg2);
    public void info(String format, Object... arguments);
    public void info(String msg, Throwable t);
}

3)校驗(yàn)參數(shù)的有效性

大部分方法都會(huì)對(duì)入?yún)⒌闹涤幸欢ㄏ拗?,比如String字符串長(zhǎng)度,類型轉(zhuǎn)換,對(duì)象不能為null,訂單運(yùn)單唯一性,批量接口List個(gè)數(shù)限制等。首先我們應(yīng)該在API中詳細(xì)描述入?yún)⒌母鞣N限制條件,并且在方法體的入口進(jìn)行校驗(yàn)檢查,以強(qiáng)制實(shí)施這些限制。

對(duì)參數(shù)的檢查,原則是盡早檢查,否則整個(gè)鏈路被檢測(cè)的可能性降低,并且一旦檢測(cè)到,定位起源頭比較復(fù)雜。反過(guò)來(lái)思考,如果不在開頭進(jìn)行檢查,則可能發(fā)生如下情況:方法在接下來(lái)鏈路處理過(guò)程中拋出錯(cuò)誤的結(jié)果,但方法可能是正常返回,比如接口返回正常,但數(shù)據(jù)庫(kù)保持的時(shí)候,由于字段越界導(dǎo)致保存數(shù)據(jù)庫(kù)異常。

?

參數(shù)校驗(yàn) 應(yīng)該反應(yīng)到 技術(shù)指標(biāo)還是業(yè)務(wù)指標(biāo)?

技術(shù)指標(biāo):個(gè)人理解入?yún)⒎欠ú粦?yīng)該體現(xiàn)到UMP技術(shù)可用率指標(biāo),因?yàn)檫@是API正常的一種體現(xiàn),如果入?yún)⒎欠ú缓侠?,返回上游?duì)應(yīng)的錯(cuò)誤碼CODE,本身的技術(shù)可用率正常。 業(yè)務(wù)指標(biāo):但方法對(duì)應(yīng)的業(yè)務(wù)指標(biāo)可以反映入?yún)⒎欠ǖ那闆r。例如,可以記錄非法入?yún)⒌拇螖?shù),以便分析和改進(jìn)整個(gè)鏈路的業(yè)務(wù)邏輯。

?

?案例:鏈路校驗(yàn)一致 比如某個(gè)入?yún)?,從上游到整個(gè)鏈路下游,包括方法內(nèi)部鏈路,最終到數(shù)據(jù)庫(kù)存儲(chǔ),校驗(yàn)規(guī)則是一致的。在下面這個(gè)例子中,userName的長(zhǎng)度限制在方法入口和數(shù)據(jù)庫(kù)存儲(chǔ)過(guò)程中保持一致,確保鏈路校驗(yàn)一致。

public class UserService {

    // 用戶信息保存方法
    public void saveUser(String userName) {
        // 參數(shù)校驗(yàn)
        if (userName == null || userName.length() > 20) {
            throw new IllegalArgumentException("User name cannot be null and must be less than 20 characters");
        }

        // 假設(shè)數(shù)據(jù)庫(kù)字段長(zhǎng)度限制為 20
        saveToDatabase(userName);
    }

    private void saveToDatabase(String userName) {
        // 數(shù)據(jù)庫(kù)保存邏輯
        // ...
    }
}

?錯(cuò)誤案例:鏈路校驗(yàn)規(guī)則不一致 零售C端/B端用戶可以填寫20個(gè)字符串,整個(gè)鏈路校驗(yàn)也是20,但底層數(shù)據(jù)庫(kù)是varchar(10)

   // 假設(shè)數(shù)據(jù)庫(kù)字段長(zhǎng)度限制為 10
    private void saveToDatabase(String userName) {
        // 數(shù)據(jù)庫(kù)保存邏輯
        // ...
    }

探討:鏈路重復(fù)校驗(yàn)

比如物流鏈路運(yùn)單合法性校驗(yàn),N個(gè)系統(tǒng)都進(jìn)行校驗(yàn)是否有必要?是否應(yīng)該只在入口處校驗(yàn),其他鏈路保持信任機(jī)制?

?

二、方法體

1)方法要短小

方法的第一規(guī)則是短小,正如行業(yè)很多代碼規(guī)約,比如阿里規(guī)約方法總行數(shù)不超過(guò)80行,京東代碼規(guī)范中方法體的行數(shù)不能多于70行,否則降低編碼效率,不方便閱讀和理解。

其實(shí)個(gè)人理解不用太關(guān)注多少行,核心是方法的職責(zé)要單一,分清楚方法主干和分支,,看方法里的代碼是否還可以再抽取一個(gè)方法,分清代碼個(gè)性和共性,把共性的代碼抽取方法,用于復(fù)用,讓方法主干更清晰。

?

2)無(wú)副作用

在Java 編程語(yǔ)言中,術(shù)語(yǔ)“副作用”(side effects) 指的是一個(gè)函數(shù)或表達(dá)式在計(jì)算結(jié)果以外對(duì)程序狀態(tài)(如修改全局變量、改變輸入?yún)?shù)的值、進(jìn)行I/O 操作等)產(chǎn)生的影響。

?

?副作用案例: 如下filterBusinessType方法的主要作用是返回一個(gè)業(yè)務(wù)類型int類型的值,但它也修改了傳入的response對(duì)象的A值作為一個(gè)副作用。在外面鏈路使用了A屬性值做邏輯判斷 副作用問題:在filterBusinessType方法中如果是在response之前return了數(shù)據(jù),從方法角度看不出問題,但整個(gè)鏈路會(huì)出現(xiàn)問題。

public int filterBusinessType( Request request,Response response) {
 if(...){
  return ... 
  }
   boolean flag = isXXX(request, response); 
} 

正如上面說(shuō)的方法職責(zé)單一,只做一件事,但副作用就是一個(gè)謊言,方法還會(huì)做其他隱藏起來(lái)的事情,我們需要理解副作用的存在,并采取合適的策略來(lái)管理和控制它們。

如何規(guī)避這種現(xiàn)象

為了避免這種情況,可以采用以下幾種策略:

1.分離關(guān)注點(diǎn): 可以將獲取業(yè)務(wù)類型和響應(yīng)設(shè)置分離成兩個(gè)不同的方法。這樣,調(diào)用者就可以清晰地看到每個(gè)方法的職責(zé)。

public int filterBusinessType(String logPrefix,Request request){
    // 過(guò)濾邏輯...
    int businessType=...;
    return businessType;
}
public void setResponseData(int filterResult,Response response){
    // 根據(jù)過(guò)濾結(jié)果設(shè)置響應(yīng)數(shù)據(jù)...
    response.setFilteredData(...);
}


1.返回復(fù)合對(duì)象(上下文context): 如果業(yè)務(wù)類型結(jié)果和響應(yīng)數(shù)據(jù)是緊密相關(guān)的,可以考慮創(chuàng)建一個(gè)包含這兩個(gè)信息的復(fù)合對(duì)象,并將其作為方法的返回值。

public FilterResultAndResponse filterBusinessType(String logPrefix,Request request){
    // 過(guò)濾邏輯...
    int result=...;
    Response response=new Response();
    response.setFilteredData(...);
    return new FilterResultAndResponse(result, response);
}

class FilterResultAndResponse{
    private int filterResult;
    private Response response;
    
    public FilterResultAndResponse(int filterResult,Response response){
        this.filterResult = filterResult;
        this.response = response;
    }
    
    // Getters and setters for filterResult and response}


3)控制語(yǔ)句(if/else/while/for等)

不要在條件判斷中執(zhí)行復(fù)雜的語(yǔ)句,將復(fù)雜邏輯判斷的結(jié)果賦值給一個(gè)有意義的布爾變量,以提高可讀性。團(tuán)隊(duì)中也存在很多if語(yǔ)句內(nèi)的邏輯相當(dāng)復(fù)雜,閱讀者需要分析條件表達(dá)式的最終結(jié)果,才能明確什么樣的條件執(zhí)行什么樣的語(yǔ)句。復(fù)雜邏輯表達(dá)式,與、或、取反混合運(yùn)算,甚至各種方法縱深調(diào)用,理解成本非常高。如果賦值一個(gè)非常好理解的布爾變量名字,則是件令人爽心悅目的事情

?

?錯(cuò)誤案例:if/else if語(yǔ)句中條件邏輯復(fù)雜,并且還存在!取反混合運(yùn)算,導(dǎo)致這段代碼理解成本比較高

boolean flagA = isKaWhiteFlag(logPrefix, request);
boolean flagB = PlatformTypeEnum.JD_STATION.getValue() == request.getPlatformType();
boolean flagC = KaPromiseUccSwitch.isPopJDDeliverySwitch(request.getDict(),request.getStoreId()) 
                           && (PlatformTypeEnum.JD_STATION.getValue() == request.getPlatformType())
                           && (DeliveryTypeEnum.JD_DELIVERY.getType() == request.getDeliveryType());
if (!flagC && flagA) {
......
}else if (!flagB && !flagC && 
          StringUtils.isNotBlank(request.getProductCode()) 
         && kaPromiseSwitch.isKaStoreRouterDs(logPrefix.getLogPrefix(), request.getDict(), request.getStoreId(), request.getCalculateTime(),request.getDeptNo())){
......
}else{
......
}

4)異常

4.1)異常應(yīng)該僅用于異常的情況,不應(yīng)該用于普通的控制流程

?案例:不當(dāng)使用異常處理控制流程

   // 使用異常處理來(lái)控制流程
    public static int parseNumber(String number) {
        try {
            return Integer.parseInt(number);
        } catch (NumberFormatException e) {
            throw e;
        }
    }

?案例:使用常規(guī)控制結(jié)構(gòu)替代異常處理

  // 使用常規(guī)控制結(jié)構(gòu)來(lái)處理正常流程
    public static boolean isNumeric(String str) {
        if (str == null) {
            return false;
        }
        try {
            Integer.parseInt(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

4.2)不要忽略異常

很多代碼都違法了這一條原則,所以本文值得再?gòu)?qiáng)調(diào)。當(dāng)方法會(huì)拋出一個(gè)異常時(shí),就是想要告訴你一些重要信息,所以不要忽略它。忽略它很簡(jiǎn)單,catch住,然后里面什么也不做。異常就是強(qiáng)制我們要處理的,空的catch違背了異常的本意,是一種不好的實(shí)踐。它不僅違背了異常處理的本意,還可能導(dǎo)致潛在的問題未被發(fā)現(xiàn)和解決。

?錯(cuò)誤案例

 try {
       
        // 可能拋出IOException
        throw new IOException("File not found");
    } catch (IOException e) {
        // 空的catch塊,忽略異常
    }

4.3)異常封裝

對(duì)于業(yè)務(wù)層面的異常,應(yīng)當(dāng)進(jìn)行適當(dāng)?shù)姆庋b,定義統(tǒng)一的異常模型。避免直接將底層異常暴露給上層模塊,以保持業(yè)務(wù)邏輯的清晰性。比如DependencyFailureException:表示服務(wù)端依賴的其他服務(wù)出現(xiàn)錯(cuò)誤,服務(wù)端是不可用的,可以嘗試重試,類比HTTP的5XX響應(yīng)狀態(tài)碼。InternalFailureException:表示服務(wù)端自身出現(xiàn)錯(cuò)誤,服務(wù)端是不可用的,可以嘗試重試,類比HTTP的5XX響應(yīng)狀態(tài)碼。

4.4)異常轉(zhuǎn)換

1.Web 層絕不應(yīng)該繼續(xù)往上拋異常,因?yàn)橐呀?jīng)處于頂層,無(wú)繼續(xù)處理異常的方式,如果意識(shí)到這個(gè)異常將導(dǎo)致頁(yè)面無(wú)法正常渲染,那么就應(yīng)該直接跳轉(zhuǎn)到友好錯(cuò)誤頁(yè)面,加上友好的錯(cuò)誤提示信息。

2.開放接口層不能直接拋異常,應(yīng)該將異常處理成code錯(cuò)誤碼和錯(cuò)誤信息message方式返回。其中錯(cuò)誤碼應(yīng)該能夠快速識(shí)別錯(cuò)誤的來(lái)源,便于團(tuán)隊(duì)成員快速定位問題。同時(shí),錯(cuò)誤碼應(yīng)易于比對(duì),有助于團(tuán)隊(duì)對(duì)錯(cuò)誤原因達(dá)成共識(shí)。其中錯(cuò)誤編碼可參考HTTP協(xié)議的響應(yīng)狀態(tài)碼:

?2XX(成功響應(yīng)):表示操作被成功接收并處理。例如,200表示請(qǐng)求成功。

?4XX(客戶端錯(cuò)誤):表示請(qǐng)求包含語(yǔ)法錯(cuò)誤或無(wú)法完成請(qǐng)求。例如,404表示請(qǐng)求的資源(網(wǎng)頁(yè)等)不存在。

?5XX(服務(wù)端錯(cuò)誤):表示服務(wù)器在處理請(qǐng)求的過(guò)程中發(fā)生了錯(cuò)誤。例如,500表示服務(wù)器內(nèi)部錯(cuò)誤,無(wú)法完成請(qǐng)求。

5)日志

5.1)日志三字經(jīng):準(zhǔn)、懂、少

準(zhǔn):日志打印一定要準(zhǔn)確,該打的地方打,不該打的地方不打。如何確定什么地方該打,原則之一看上線后日志是否可以覆蓋方法的所有業(yè)務(wù)場(chǎng)景

懂:打印日志不只是給你自己看的,更是給團(tuán)隊(duì)其他人看的,所以一定要打印的讓其他人也能看懂,盡量用一些通俗易懂的文字描述讓團(tuán)隊(duì)能看懂

少:少即是多,日志太多第一影響性能,第二存儲(chǔ)成本,第三影響排查

?

5.2)日志注意事項(xiàng)

1.日志必須有traceId,可追蹤唯一性

2.日志打印建議打中文結(jié)合代碼英文字段方法屬性等,確保日志內(nèi)容清晰、易于理解和分析,否則看完日志還得去看代碼

3.對(duì)外API方法出入?yún)⒈仨毚蛴?/p>

4.調(diào)用其他團(tuán)隊(duì)API(JSF接口、中間件Redis等)同理,必須打印出入?yún)?/p>

5.異常信息要打印

6.不用打重復(fù)日志,比如在DAO層,由于可能會(huì)遇到多種類型的異常,DAO層不需要打印日志。這是因?yàn)樵贛anager或Service層,異常會(huì)被再次捕獲并記錄到日志文件中。

7.在 Service 層出現(xiàn)異常時(shí),必須記錄出錯(cuò)日志到磁盤,其中日志記錄應(yīng)該遵循一定的規(guī)范,包括錯(cuò)誤碼、異常信息和必要的上下文信息。日志內(nèi)容應(yīng)該清晰明了,相當(dāng)于保護(hù)案發(fā)現(xiàn)場(chǎng)。

?案例:團(tuán)隊(duì)日志我一直想治理,其中2個(gè)痛點(diǎn):第一個(gè)是打印的太多,第二個(gè)是很多日志只有當(dāng)事人能看懂,其他成員看不懂

?

6)詳細(xì)的注釋

詳細(xì)的代碼注釋在方法中至關(guān)重要,原因如下:

1.業(yè)務(wù)迭代:隨著業(yè)務(wù)的不斷迭代,許多方法的意圖變得難以理解。

2.有坑的代碼:團(tuán)隊(duì)中存在非常規(guī)、有坑的代碼,增加了維護(hù)的難度。

3.人員變更:團(tuán)隊(duì)成員的變動(dòng)使得代碼的可讀性和可維護(hù)性變得更加重要。

方法注釋的要點(diǎn)

1.描述方法和客戶端之間的約定:注釋應(yīng)詳細(xì)描述方法的功能和其與調(diào)用方之間的約定,即方法應(yīng)該完成什么任務(wù)。

2.列出前置條件:注釋應(yīng)列出所有調(diào)用該方法前必須滿足的條件。這可以幫助調(diào)用者理解在什么情況下可以安全地調(diào)用該方法。

3.列出后置條件:注釋應(yīng)明確調(diào)用方法后哪些條件肯定會(huì)成立。這有助于調(diào)用者了解調(diào)用方法后的預(yù)期結(jié)果和狀態(tài)變化。

4.描述副作用:如果方法有任何副作用,如啟動(dòng)后臺(tái)線程或修改入?yún)?duì)象的某個(gè)值,這些都應(yīng)該在注釋中詳細(xì)說(shuō)明。這可以幫助調(diào)用者預(yù)見和處理可能的影響。

public int filterBusinessType( Request request,Response response) {
 /** * 切記:return必須在下面這行代碼(isXXX方法)后面,因?yàn)橥饷鏁?huì)使用response.A()來(lái)判斷邏輯 
     * 你可以理解本filterBusinessType方法會(huì)返回業(yè)務(wù)類型,同時(shí)如果isXXX方法會(huì)修改response.setA()屬性 
 */ 
 boolean flag = isXXX(request, response); 
 if(...){
  return ... 
 } 
 } 

對(duì)外API文檔

對(duì)于對(duì)外的API文檔,注釋應(yīng)詳細(xì)說(shuō)明每個(gè)字段的條件,確保調(diào)用方能夠無(wú)歧義地理解API的使用。關(guān)于API文檔的細(xì)節(jié),在此不做詳細(xì)討論,但同樣需要強(qiáng)調(diào)清晰和詳細(xì)的重要性。

?

通過(guò)詳細(xì)的注釋,能夠提高代碼的可讀性和可維護(hù)性,減少因業(yè)務(wù)迭代、歷史代碼和人員變更帶來(lái)的困擾。

?

?案例:針對(duì)時(shí)效內(nèi)核,代碼比較抽象,添加的詳細(xì)注釋詳細(xì),加一下case案例,方便新人可讀性

?注意點(diǎn): 1、注釋會(huì)撒謊,代碼注釋的時(shí)間越久,就離其代碼的本意越遠(yuǎn),越來(lái)越變得錯(cuò)誤,原因很簡(jiǎn)單:程序員不能堅(jiān)持維護(hù)注釋。 2、不準(zhǔn)確的注釋比沒注釋壞的多,只有代碼能忠實(shí)的告訴你告訴你它做的事,那是唯一真正準(zhǔn)確的信息來(lái)源

三、出參

1)返回空的集合或者數(shù)組,而不是null

如果方法返回null,而不是空的集合或者數(shù)組,那么幾乎所有使用這個(gè)方法的地方,都需要特殊判斷null,這樣很容易由于遺忘而出錯(cuò),


?

如本文里面信息不對(duì)請(qǐng)指正,如有更好的知識(shí)點(diǎn),歡迎評(píng)論交流完善補(bǔ)充。謝謝!


?

相關(guān)文獻(xiàn)

1、Effective Java

2、Clean Code

3、京東JAVA代碼規(guī)范

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2966

    瀏覽量

    104700
  • effective
    +關(guān)注

    關(guān)注

    0

    文章

    4

    瀏覽量

    6723
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    c++java轉(zhuǎn)變的注意點(diǎn)

    ,方法可以檢驗(yàn)這些并且在異常產(chǎn)生的時(shí)候拋出異常。在大多數(shù)系統(tǒng)中,程序員并不是必須這樣做,這樣,一個(gè)沒有考慮的異??梢允钩绦虿徽5耐顺?。在Java中,異常已經(jīng)成為非常成熟的部分。方法
    發(fā)表于 09-22 12:39

    [下載][推薦]超實(shí)用的java項(xiàng)目實(shí)踐視頻

    [推薦]超實(shí)用的java項(xiàng)目實(shí)踐視頻   我學(xué)java很長(zhǎng)時(shí)間了,一直在尋找項(xiàng)目視頻,最近看了北風(fēng)網(wǎng)上推出的java私塾項(xiàng)目視頻,感覺很不錯(cuò)。其中需求分析,系統(tǒng)
    發(fā)表于 12-07 16:17

    [轉(zhuǎn)帖]java項(xiàng)目實(shí)踐視頻

    java項(xiàng)目實(shí)踐視頻  java私塾推出的項(xiàng)目視頻,感覺很不錯(cuò),其中需求分析,系統(tǒng)架構(gòu)設(shè)計(jì)很合理。對(duì)正在做畢業(yè)設(shè)計(jì)的同學(xué)有很大幫助。 課程大綱: &
    發(fā)表于 05-17 14:47

    全新java初學(xué)者實(shí)踐教程

    java 這套技術(shù)。要想掌握這套技術(shù)實(shí)踐是非常重要的。那么很多初學(xué)者,在第一步實(shí)踐的時(shí)候就遇到了困難,就是配置環(huán)境變量。以至于,因無(wú)法繼續(xù)實(shí)踐而苦惱。下面為了幫廣大愛好者解決這個(gè)問題,
    發(fā)表于 08-07 22:24

    Java學(xué)習(xí)經(jīng):提高Java培訓(xùn)效率的6個(gè)方法

      初學(xué)Java就像交朋友陌生熟悉再到鐵桿搭檔一生相伴,隨著學(xué)習(xí)的深入,你會(huì)發(fā)現(xiàn)學(xué)Java并不是想象的那樣枯燥和困難,甚至還有一些美妙之感,這是在擁有強(qiáng)大的技術(shù)和出色的設(shè)計(jì)思想后才
    發(fā)表于 10-19 11:05

    全新java基礎(chǔ)實(shí)踐教程.chm

    全新java基礎(chǔ)實(shí)踐教程:最近我發(fā)現(xiàn)不少初學(xué)者,學(xué)習(xí)java的時(shí)候,看了好多java的歷史、優(yōu)點(diǎn)和應(yīng)用范圍。對(duì)于這些知識(shí),并不難理解。我也當(dāng)然同意j
    發(fā)表于 12-08 10:33 ?0次下載

    Java零基礎(chǔ)精通的整個(gè)詳細(xì)筆記

    Java零基礎(chǔ)精通的整個(gè)詳細(xì)筆記。
    發(fā)表于 11-06 11:24 ?0次下載

    JAVA教程之網(wǎng)絡(luò)取得文件

    JAVA教程之網(wǎng)絡(luò)取得文件,很好的JAVA的資料,快來(lái)學(xué)習(xí)吧
    發(fā)表于 04-11 17:28 ?5次下載

    JAVA教程之網(wǎng)絡(luò)上下載數(shù)據(jù)

    JAVA教程之網(wǎng)絡(luò)上下載數(shù)據(jù),很好的JAVA的資料,快來(lái)下載吧。
    發(fā)表于 04-13 11:34 ?7次下載

    java入門精通

    java學(xué)習(xí)入門精通,很好的學(xué)習(xí)書。。。。。。。。。。。。
    發(fā)表于 05-04 17:10 ?12次下載

    Effective Java中文版

    javaEffective.Java中文版。
    發(fā)表于 05-06 14:12 ?0次下載

    java入門詳解[推薦]

    java入門詳解[推薦]
    發(fā)表于 03-19 11:23 ?4次下載

    java之父及java誕生_java之父為什么谷歌離職

    本文我們將跟隨Gosling,認(rèn)識(shí)下這位偉大的java之父,了解下他為什么谷歌離職,并將再一次見證,Java作為一種神奇的語(yǔ)言,始終站在科學(xué)最前沿。
    的頭像 發(fā)表于 02-10 09:36 ?3.5w次閱讀

    JAVA并發(fā)編程實(shí)踐

    JAVA并發(fā)編程實(shí)踐資料免費(fèi)下載。
    發(fā)表于 06-01 15:31 ?15次下載

    java內(nèi)存溢出排查方法

    模型。Java內(nèi)存模型分為線程棧、堆、方法區(qū)(Java 8之前稱為永久代,Java 8后稱為元空間)和本地方法
    的頭像 發(fā)表于 11-23 14:46 ?3217次閱讀
    RM新时代网站-首页