資深程序員入行幾年才懂的28個(gè)Java開發(fā)常用規(guī)范技巧總結(jié)!

1、類的命名使用駝峰式命名的規(guī)范。

例如:UserService,但是以下情景例外:DO / BO / PO / DTO / VO。

例如說:UserPO,StudentPO(PO,VO,DTO,等這類名詞需要全大寫)

@Data
@Builder
public class CustomBodyDTO {

    private String name;

    private String idCode;

    private String status;
}

2、如果在模塊或者接口,類,方法中使用了設(shè)計(jì)模式,那么請(qǐng)?jiān)诿臅r(shí)候體現(xiàn)出來。

例如說:TokenFactory,LoginProxy等。
public class TokenFactory {

public TokenDTO buildToken(LoginInfo loginInfo) {
    String token = UUID.randomUUID().toString();
    TokenDTO tokenDTO = TokenDTO.builder()
            .token(token)
            .createTime(LocalDateTime.now())
            .build();
    String redisKey = RedisKeyBuilder.buildTokenKey(token);
    redisService.setObject(redisKey, loginInfo, Timeout.ONE_DAY * 30 * 2);
    log.info("創(chuàng)建token成功|loginInfo={}", loginInfo.toString());
    return tokenDTO;
}

3、Object 的 equals 方法容易拋空指針異常。

從源碼來進(jìn)行分析equals方法是屬于Object類的,如果調(diào)用方為null,那么自然在運(yùn)行的時(shí)候會(huì)拋出空指針異常的情況。

object類中的源碼:

public boolean equals(Object obj) {
       return (this == obj);
   }

為了避免這種現(xiàn)況出現(xiàn),在比對(duì)的時(shí)候盡量將常量或者有確定值的對(duì)象置前。

例如說:

正確:“test”.equals(object);
錯(cuò)誤:object.equals(“test”);

4、對(duì)于所有相同類型的包裝類進(jìn)行比較的時(shí)候,都是用equal來進(jìn)行操作。

對(duì)于Integer類來說,當(dāng)相應(yīng)的變量數(shù)值范圍在-128到127之間的時(shí)候,該對(duì)象會(huì)被存儲(chǔ)在IntegerCache.cache里面,因此會(huì)有對(duì)象復(fù)用的情況發(fā)生。

所以對(duì)于包裝類進(jìn)行比較的時(shí)候,最好統(tǒng)一使用equal方法。

  private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

  public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

5、所有的pojo類中的屬性最好統(tǒng)一使用包裝類屬性類型數(shù)據(jù)。
RPC方法的返回值和參數(shù)都統(tǒng)一使用包裝類數(shù)據(jù)。局部變量中使用基本的數(shù)據(jù)類型。

對(duì)于實(shí)際的應(yīng)用場(chǎng)景來說,例如說一個(gè)學(xué)生類,當(dāng)我們?cè)O(shè)置里面的成績(jī)字段為int類型的時(shí)候,如果學(xué)生沒有考試,那么這個(gè)成績(jī)字段應(yīng)該為空。

但是int默認(rèn)會(huì)賦值為0,那么這個(gè)時(shí)候使用基本數(shù)據(jù)類型就容易產(chǎn)生誤區(qū),到底是考了0分,還是說沒有參加考試。

如果換成使用包裝類Integer類型的話,就可以通過null值來進(jìn)行區(qū)分了。

6、當(dāng)pojo類在進(jìn)行編寫的時(shí)候要重寫相應(yīng)的toString方法,如果該pojo中繼承了另外的一個(gè)pojo類,那么請(qǐng)?jiān)谙鄳?yīng)的tostring函數(shù)中加入super.toString()方法。

通過重寫toString方法有利于在日志輸出的時(shí)候查看相應(yīng)對(duì)象的屬性內(nèi)容進(jìn)行逐一分析,對(duì)于一些有繼承關(guān)系的對(duì)象而言,加入了super.toString方法更加有助于對(duì)該對(duì)象的理解和分析。

7、在pojo的getter和setter方法里面,不要增加業(yè)務(wù)邏輯的代碼編寫,這樣會(huì)增加問題排查的難度。

正確做法:

public class User {
    private Integer id;

    private String username;

    public Integer getId() {
        return id;
    }

    public User setId(Integer id) {
        this.id = id;
        return this;
    }

    public String getUsername() {
        return username;
    }

    public User setUsername(String username) {
        this.username = username;
        return this;
    }
}

錯(cuò)誤做法:

public class User {
    private Integer id;

    private String username;

    public Integer getId() {
        return id;
    }

    public User setId(Integer id) {
        this.id = id;
        return this;
    }

    public String getUsername() {
        return "key-prefix-"+username;
    }

    public User setUsername(String username) {
        this.username = "key-prefix-"+username;
        return this;
    }
}

8、final 可以聲明類、成員變量、方法、以及本地變量。

下列情況使用 final 關(guān)鍵字:

不允許被繼承的類,如:String 類。

不允許修改引用的域?qū)ο?,如:POJO 類的域變量。

不允許被重寫的方法,如:POJO 類的 setter 方法。

不允許運(yùn)行過程中重新賦值的局部變量。

避免上下文重復(fù)使用一個(gè)變量,使用 final 描述可以強(qiáng)制重新定義一個(gè)變量,方便更好地進(jìn)行重構(gòu)。

9、對(duì)于任何類而言,只要重寫了equals就必須重寫hashcode。

舉例說明:

1)HashSet在存儲(chǔ)數(shù)據(jù)的時(shí)候是存儲(chǔ)不重復(fù)對(duì)象的,這些對(duì)象在進(jìn)行判斷的時(shí)候需要依賴hashcode和equals方法,因此需要重寫。

2)在自定義對(duì)象作為key鍵時(shí),需要重寫hashcode和equals方法,例如說String類就比較適合用于做key來使用。

10、不要在 foreach 循環(huán)里進(jìn)行元素的 remove/add 操作。

remove 元素請(qǐng)使用 Iterator方式,如果并發(fā)操作,需要對(duì) Iterator 對(duì)象加鎖。

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (刪除元素的條件) {
iterator.remove();
}
}

11、使用HashMap的時(shí)候,可以指定集合的初始化大小。

例如說,HashMap里面需要存放10000個(gè)元素,但是由于沒有進(jìn)行初始化大小操作,所以在添加元素的時(shí)候,hashmap的內(nèi)部會(huì)一直在進(jìn)行擴(kuò)容操作,影響性能。

那么為了減少擴(kuò)容操作,可以在初始化的時(shí)候?qū)ashmap的大小設(shè)置為:已知需要存儲(chǔ)的大小/負(fù)載因子(0.75)+1

HashMap hashMap=new HashMap<>(13334);

12、Map類集合中,K/V對(duì)于null類型存儲(chǔ)的情況:

image.png

13、可以利用 Set 元素唯一的特性,可以快速對(duì)一個(gè)集合進(jìn)行去重操作,避免使用 List 的contains 方法進(jìn)行遍歷、對(duì)比、去重操作。

通關(guān)觀察可以發(fā)現(xiàn),HashSet底層通過將傳入的值再傳入到一個(gè)HashMap里面去進(jìn)行操作,進(jìn)入到HashMap里面之后,會(huì)先通過調(diào)用該對(duì)象的hashcode來判斷是否有重復(fù)的值,如果有再進(jìn)行equals判斷,如果沒有相同元素則插入處理。

 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

14、線程池不允許使用 Executors 去創(chuàng)建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。

錯(cuò)誤做法:

ExecutorService executors = Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

對(duì)于線程池的參數(shù)需要有深入的理解后,結(jié)合實(shí)際的機(jī)器參數(shù)來進(jìn)行參數(shù)設(shè)置,從而防止在使用中出現(xiàn)異常。

ExecutorService fixedExecutorService = new ThreadPoolExecutor(
            1,
            2, 
            60,
            TimeUnit.SECONDS,
             linkedBlockingQueue, 
            new MyThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
    );

ps:使用Executors.new 方式創(chuàng)建線程池的缺點(diǎn):

對(duì)于FixedThreadPool 和 SingleThreadPool而言

允許的請(qǐng)求隊(duì)列長(zhǎng)度為 Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致 OOM。

對(duì)于CachedThreadPool 和 ScheduledThreadPool而言

允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致 OOM。

15、使用一些日期類的時(shí)候,推薦使用LocalDateTime來替代Calendar類,或者說使用Instant來替代掉Date類。

16、盡量避免在for循環(huán)里面執(zhí)行try-catch操作,可以選擇將try-catch操作放在循環(huán)體外部使用。

正確做法:

try {
         for (int i = 0; i < 100; i++) {
             doSomeThing();
          }
       }catch (Exception e){
            e.printStackTrace();
       }
不推薦做法:

for (int i = 0; i < 100; i++) {

      try {
                doSomeThing();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

17、對(duì)于大段的代碼進(jìn)行try-catch操作,這是一種不負(fù)責(zé)任的行為,將穩(wěn)定的代碼也都包圍在了try-catch語(yǔ)句塊里面沒能很好的分清代碼的穩(wěn)定性范圍。

通常我們稱在運(yùn)行中不會(huì)出錯(cuò)的代碼塊為穩(wěn)定性代碼,可能會(huì)有異常出錯(cuò)的部分為非穩(wěn)定性代碼塊,后者才是try-catch重點(diǎn)需要關(guān)注的對(duì)象。

18、在jdk7之后,對(duì)于流這類需要關(guān)閉連接釋放資源的對(duì)象,可以使用try-with-resource處理機(jī)制來應(yīng)對(duì)。

例如下方代碼:

  File file = new File("*****");
        try (FileInputStream fin = new FileInputStream(file)) {
            //執(zhí)行相關(guān)操作
        } catch (Exception e) {
            //異常捕獲操作
        }

19、使用ArrayList的時(shí)候,如果清楚它的指定大小的話,可以盡量在初始化的時(shí)候進(jìn)行大小指定,因?yàn)殡S著arraylist不斷添加新的元素之后,鏈表的體積會(huì)不斷增大擴(kuò)容。

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

20、對(duì)于一些短信,郵件,電話,下單,支付等應(yīng)用場(chǎng)景而言,開發(fā)的時(shí)候需要設(shè)置相關(guān)的防重復(fù)功能限制,防止出現(xiàn)某些惡意刷單,濫刷這類型情況。

21、對(duì)于敏感詞匯發(fā)表的時(shí)候,需要考慮一些文本過濾的策略。

這一塊的功能可以考慮直接接入市面上已有的成熟的UGC監(jiān)控服務(wù),或者使用公司內(nèi)部自研的ugc過濾工具,防止用戶發(fā)表惡意評(píng)論等情況出現(xiàn)。

22、在建立索引的時(shí)候,對(duì)于索引的命名需要遵循一定的規(guī)范:


image.png

23、當(dāng)我們需要存儲(chǔ)一段文本信息的時(shí)候,需要先考慮存儲(chǔ)文本的長(zhǎng)度。

如果文本的長(zhǎng)度超過了5000,則不建議再選擇使用varchar類型來進(jìn)行存儲(chǔ),可以考慮使用text類型進(jìn)行數(shù)據(jù)存儲(chǔ),這個(gè)時(shí)候可以考慮單獨(dú)用一張表來進(jìn)行存儲(chǔ)數(shù)據(jù),并且通過一個(gè)額外的主鍵id來對(duì)應(yīng),從而避免影響其他字段的查詢。

24、在進(jìn)行數(shù)據(jù)庫(kù)命名的時(shí)候盡量保證數(shù)據(jù)庫(kù)的名稱和項(xiàng)目工程的名稱一致。

25、在進(jìn)行表結(jié)構(gòu)設(shè)計(jì)的時(shí)候,只要具有唯一性質(zhì)的字段都需要建立唯一索引。

這樣有助于后期進(jìn)行查詢的時(shí)候提高查詢的效率,沒有唯一索引這一層的保障,即使在業(yè)務(wù)層加入了攔截,但是依然容易造成線上臟數(shù)據(jù)的產(chǎn)生。

26、在進(jìn)行order by這類型sql查詢的時(shí)候,需要注意查詢索引的有序性。

關(guān)于索引的建立,可以去了解一下索引的星級(jí)評(píng)定,例如三星索引。但是個(gè)人認(rèn)為索引沒有所謂的最優(yōu)性,需要結(jié)合實(shí)際的業(yè)務(wù)場(chǎng)景來設(shè)計(jì)。

27、在MySQL中,使用count(*)會(huì)統(tǒng)計(jì)值為 NULL 的行,而 count(列名)不會(huì)統(tǒng)計(jì)此列為 NULL 值的行。

28、在進(jìn)行數(shù)據(jù)庫(kù)存儲(chǔ)引擎選擇的時(shí)候,需要結(jié)合相關(guān)的應(yīng)用場(chǎng)景來選擇,如果是需要應(yīng)用在select操作較多的情況下,可以選擇使用MyIsAM存儲(chǔ)引擎,如果是對(duì)于數(shù)據(jù)的insert,update,這類修改操作較多的業(yè)務(wù)場(chǎng)景,則優(yōu)先推薦使用innodb存儲(chǔ)引擎。 目前普遍互聯(lián)網(wǎng)公司都推薦使用innodb較多。

參考

阿里巴巴Java開發(fā)手冊(cè)

碼字不易如有發(fā)現(xiàn)文章錯(cuò)誤歡迎在討論區(qū)留言 感謝大家能看我文章 后面我會(huì)持續(xù)更新的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容