阿里巴巴Java開(kāi)發(fā)手冊(cè)閱讀筆記

前言

參考:阿里巴巴Java開(kāi)發(fā)手冊(cè)V1.3.0

總結(jié)比較重要的,對(duì)面試有用的開(kāi)發(fā)規(guī)約

一、編程規(guī)約

(一)命名風(fēng)格

  • 【強(qiáng)制】POJO 類中布爾類型的變量,都不要加 is,否則部分框架解析會(huì)引起序列化錯(cuò)誤。

反例:定義為基本數(shù)據(jù)類型 Boolean isDeleted;的屬性,它的方法也是 isDeleted(),RPC
框架在反向解析的時(shí)候,“以為”對(duì)應(yīng)的屬性名稱是 deleted,導(dǎo)致屬性獲取不到,進(jìn)而拋出異常。

  • 【推薦】如果模塊、接口、類、方法使用了設(shè)計(jì)模式,在命名時(shí)體現(xiàn)出具體模式。

public class OrderFactory;

public class LoginProxy;

public class ResourceObserver;

(二)常量定義

  • 【強(qiáng)制】不允許任何魔法值(即未經(jīng)定義的常量)直接出現(xiàn)在代碼中。

反例:String key = "Id#taobao_" + tradeId;

cache.put(key, value);

  • 【推薦】如果變量值僅在一個(gè)范圍內(nèi)變化,且?guī)в忻Q之外的延伸屬性,定義為枚舉類。

正例:public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6),
SUNDAY(7);}

(三)代碼格式

(四)OOP 規(guī)約

  • 【強(qiáng)制】避免通過(guò)一個(gè)類的對(duì)象引用訪問(wèn)此類的靜態(tài)變量或靜態(tài)方法,無(wú)謂增加編譯器解析成本,直接用類名來(lái)訪問(wèn)即可。

  • 【強(qiáng)制】外部正在調(diào)用或者二方庫(kù)依賴的接口,不允許修改方法簽名,避免對(duì)接口調(diào)用方產(chǎn)生影響。接口過(guò)時(shí)必須加@Deprecated 注解,并清晰地說(shuō)明采用的新接口或者新服務(wù)是什么。

  • 【強(qiáng)制】所有的相同類型的包裝類對(duì)象之間值的比較,全部使用 equals 方法比較。

說(shuō)明:對(duì)于 Integer var = ? 在-128 至 127 范圍內(nèi)的賦值,Integer 對(duì)象是在IntegerCache.cache 產(chǎn)生,會(huì)復(fù)用已有對(duì)象,這個(gè)區(qū)間內(nèi)的 Integer值可以直接使用==進(jìn)行判斷,但是這個(gè)區(qū)間之外的所有數(shù)據(jù),都會(huì)在堆上產(chǎn)生,并不會(huì)復(fù)用已有對(duì)象,這是一個(gè)大坑,推薦使用 equals 方法進(jìn)行判斷。

  • 【強(qiáng)制】序列化類新增屬性時(shí),請(qǐng)不要修改 serialVersionUID 字段,避免反序列失?。蝗绻耆患嫒萆?jí),避免反序列化混亂,那么請(qǐng)修改 serialVersionUID 值。

說(shuō)明:注意 serialVersionUID 不一致會(huì)拋出序列化運(yùn)行時(shí)異常。

  • 【強(qiáng)制】構(gòu)造方法里面禁止加入任何業(yè)務(wù)邏輯,如果有初始化邏輯,請(qǐng)放在 init 方法中。

  • 【強(qiáng)制】POJO 類必須寫 toString 方法。使用 IDE 的中工具:source> generate toString
    時(shí),如果繼承了另一個(gè) POJO 類,注意在前面加一下 super.toString。

說(shuō)明:在方法執(zhí)行拋出異常時(shí),可以直接調(diào)用 POJO 的 toString()方法打印其屬性值,便于排
查問(wèn)題。

  • 【推薦】循環(huán)體內(nèi),字符串的連接方式,使用 StringBuilder 的 append 方法進(jìn)行擴(kuò)展。

說(shuō)明:反編譯出的字節(jié)碼文件顯示每次循環(huán)都會(huì) new 出一個(gè) StringBuilder 對(duì)象,然后進(jìn)行
append 操作,最后通過(guò) toString 方法返回 String 對(duì)象,造成內(nèi)存資源浪費(fèi)。

反例:

String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello";
}

(五)集合處理

  • 【強(qiáng)制】關(guān)于 hashCode 和 equals 的處理,遵循如下規(guī)則:
    • 1) 只要重寫 equals,就必須重寫 hashCode。
    • 2) 因?yàn)?Set 存儲(chǔ)的是不重復(fù)的對(duì)象,依據(jù) hashCode 和 equals 進(jìn)行判斷,所以 Set 存儲(chǔ)的對(duì)象必須重寫這兩個(gè)方法。
    • 3) 如果自定義對(duì)象做為 Map 的鍵,那么必須重寫 hashCode 和 equals。

說(shuō)明:String 重寫了 hashCode 和 equals 方法,所以我們可以非常愉快地使用 String 對(duì)象
作為 key 來(lái)使用。

  • 【強(qiáng)制】ArrayList的subList結(jié)果不可強(qiáng)轉(zhuǎn)成ArrayList,否則會(huì)拋出ClassCastException
    異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.

說(shuō)明:subList 返回的是 ArrayList 的內(nèi)部類 SubList,并不是 ArrayList ,而是
ArrayList 的一個(gè)視圖,對(duì)于 SubList 子列表的所有操作最終會(huì)反映到原列表上。

  • 【強(qiáng)制】使用集合轉(zhuǎn)數(shù)組的方法,必須使用集合的 toArray(T[] array),傳入的是類型完全一樣的數(shù)組,大小就是 list.size()。

反例:直接使用 toArray 無(wú)參方法存在問(wèn)題,此方法返回值只能是 Object[]類,若強(qiáng)轉(zhuǎn)其它
類型數(shù)組將出現(xiàn) ClassCastException 錯(cuò)誤。

  • 【強(qiáng)制】使用工具類Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時(shí),不能使用其修改集合相關(guān)的方法,它的 add/remove/clear 方法會(huì)拋出 UnsupportedOperationException 異常。

說(shuō)明:asList 的返回對(duì)象是一個(gè) Arrays 內(nèi)部類,并沒(méi)有實(shí)現(xiàn)集合的修改方法。Arrays.asList
體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺(tái)的數(shù)據(jù)仍是數(shù)組。
String[] str = new String[] { "you", "wu" };
List list = Arrays.asList(str);

第一種情況:list.add("yangguanbao"); 運(yùn)行時(shí)異常。

第二種情況:str[0] = "gujin"; 那么 list.get(0)也會(huì)隨之修改。

  • 【強(qiáng)制】不要在 foreach 循環(huán)里進(jìn)行元素的 remove/add 操作。remove 元素請(qǐng)使用 Iterator方式,如果并發(fā)操作,需要對(duì) Iterator 對(duì)象加鎖。

  • 【推薦】高度注意 Map 類集合 K/V 能不能存儲(chǔ) null 值的情況,如下表格:

在這里插入圖片描述

(六)并發(fā)處理

  • 【強(qiáng)制】線程資源必須通過(guò)線程池提供,不允許在應(yīng)用中自行顯式創(chuàng)建線程。

說(shuō)明:使用線程池的好處是減少在創(chuàng)建和銷毀線程上所花的時(shí)間以及系統(tǒng)資源的開(kāi)銷,解決資
源不足的問(wèn)題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者
“過(guò)度切換”的問(wèn)題。

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

  • 【推薦】避免 Random 實(shí)例被多線程使用,雖然共享該實(shí)例是線程安全的,但會(huì)因競(jìng)爭(zhēng)同一seed 導(dǎo)致的性能下降。

說(shuō)明:Random 實(shí)例包括 java.util.Random 的實(shí)例或者 Math.random()的方式。

正例:在 JDK7 之后,可以直接使用 API ThreadLocalRandom,而在 JDK7 之前,需要編碼保
證每個(gè)線程持有一個(gè)實(shí)例。

  • 【參考】volatile 解決多線程內(nèi)存不可見(jiàn)問(wèn)題。對(duì)于一寫多讀,是可以解決變量同步問(wèn)題,但是如果多寫,同樣無(wú)法解決線程安全問(wèn)題。如果是count++操作,使用如下類實(shí)現(xiàn):AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推薦使用 LongAdder 對(duì)象,比 AtomicLong 性能更好(減少樂(lè)觀鎖的重試次數(shù))。

(七)控制語(yǔ)句

  • 【推薦】表達(dá)異常的分支時(shí),少用 if-else 方式

說(shuō)明:如果非得使用 if()...else if()...else...方式表達(dá)邏輯,【強(qiáng)制】避免后續(xù)代碼維
護(hù)困難,請(qǐng)勿超過(guò) 3 層。
正例:超過(guò) 3 層的 if-else 的邏輯判斷代碼可以使用衛(wèi)語(yǔ)句、策略模式、狀態(tài)模式等來(lái)實(shí)現(xiàn),
其中衛(wèi)語(yǔ)句示例如下:

public void today() {
 if (isBusy()) {
System.out.println(“change time.”);
 return;
 }
 if (isFree()) {
System.out.println(“go to travel.”);
 return;
 }
 System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”);
 return;
}

(八)注釋規(guī)約

(九)其它

  • 【強(qiáng)制】在使用正則表達(dá)式時(shí),利用好其預(yù)編譯功能,可以有效加快正則匹配速度。

  • 【強(qiáng)制】后臺(tái)輸送給頁(yè)面的變量必須加$!{var}——中間的感嘆號(hào)。

說(shuō)明:如果 var=null 或者不存在,那么${var}會(huì)直接顯示在頁(yè)面上。

  • 【強(qiáng)制】注意 Math.random() 這個(gè)方法返回是 double 類型,注意取值的范圍 0≤x<1(能夠
    取到零值,注意除零異常),如果想獲取整數(shù)類型的隨機(jī)數(shù),不要將 x 放大 10 的若干倍然后
    取整,直接使用 Random 對(duì)象的 nextInt 或者 nextLong 方法。

二、異常日志

(一)異常處理

  • 【強(qiáng)制】Java 類庫(kù)中定義的一類 RuntimeException 可以通過(guò)預(yù)先檢查進(jìn)行規(guī)避,而不應(yīng)該
    通過(guò) catch 來(lái)處理,比如:IndexOutOfBoundsException,NullPointerException 等等。

正例:if (obj != null) {...}

反例:try { obj.method() } catch (NullPointerException e) {...}

  • 【強(qiáng)制】異常不要用來(lái)做流程控制,條件控制,因?yàn)楫惓5奶幚硇时葪l件分支低。

  • 【強(qiáng)制】對(duì)大段代碼進(jìn)行 try-catch,這是不負(fù)責(zé)任的表現(xiàn)

  • 【強(qiáng)制】捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請(qǐng)
    將該異常拋給它的調(diào)用者。最外層的業(yè)務(wù)使用者,必須處理異常,將其轉(zhuǎn)化為用戶可以理解的
    內(nèi)容。

  • 【推薦】防止 NPE,是程序員的基本修養(yǎng).

  • 【參考】在代碼中使用“拋異?!边€是“返回錯(cuò)誤碼”,對(duì)于公司外的 http/api 開(kāi)放接口必須
    使用“錯(cuò)誤碼”;而應(yīng)用內(nèi)部推薦異常拋出;跨應(yīng)用間 RPC 調(diào)用優(yōu)先考慮使用 Result 方式,封
    裝 isSuccess()方法、“錯(cuò)誤碼”、“錯(cuò)誤簡(jiǎn)短信息”

(二)日志規(guī)約

  • 【強(qiáng)制】日志文件推薦至少保存 15 天,因?yàn)橛行┊惓>邆湟浴爸堋睘轭l次發(fā)生的特點(diǎn)。

  • 【強(qiáng)制】應(yīng)用中不可直接使用日志系統(tǒng)(Log4j、Logback)中的 API,而應(yīng)依賴使用日志框架SLF4J中的API,使用門面模式的日志框架,有利于維護(hù)和各個(gè)類的日志處理方式統(tǒng)一。

三、單元測(cè)試

  • 【強(qiáng)制】好的單元測(cè)試必須遵守 AIR 原則。
    說(shuō)明:?jiǎn)卧獪y(cè)試在線上運(yùn)行時(shí),感覺(jué)像空氣(AIR)一樣并不存在,但在測(cè)試質(zhì)量的保障上,
    卻是非常關(guān)鍵的。好的單元測(cè)試宏觀上來(lái)說(shuō),具有自動(dòng)化、獨(dú)立性、可重復(fù)執(zhí)行的特點(diǎn)。
    • A:Automatic(自動(dòng)化)
    • I:Independent(獨(dú)立性)
    • R:Repeatable(可重復(fù))

四、安全規(guī)約

  • 【強(qiáng)制】隸屬于用戶個(gè)人的頁(yè)面或者功能必須進(jìn)行權(quán)限控制校驗(yàn)。

  • 【強(qiáng)制】用戶輸入的 SQL 參數(shù)嚴(yán)格使用參數(shù)綁定或者 METADATA 字段值限定,防止 SQL 注入,
    禁止字符串拼接 SQL 訪問(wèn)數(shù)據(jù)庫(kù)。

  • 【強(qiáng)制】用戶請(qǐng)求傳入的任何參數(shù)必須做有效性驗(yàn)證。

五、MySQL 數(shù)據(jù)庫(kù)

(一) 建表規(guī)約

  • 【強(qiáng)制】如果存儲(chǔ)的字符串長(zhǎng)度幾乎相等,使用 char 定長(zhǎng)字符串類型。

  • 【強(qiáng)制】表達(dá)是與否概念的字段,必須使用 is _ xxx 的方式命名,數(shù)據(jù)類型是 unsigned tinyint( 1 表示是,0 表示否 )

    • 說(shuō)明:任何字段如果為非負(fù)數(shù),必須是 unsigned 。
    • 正例:表達(dá)邏輯刪除的字段名 is_deleted ,1 表示刪除,0 表示未刪除。
  • 【強(qiáng)制】 varchar 是可變長(zhǎng)字符串,不預(yù)先分配存儲(chǔ)空間,長(zhǎng)度不要超過(guò) 5000,如果存儲(chǔ)長(zhǎng)
    度大于此值,定義字段類型為 text ,獨(dú)立出來(lái)一張表,用主鍵來(lái)對(duì)應(yīng),避免影響其它字段索
    引效率。

  • 【強(qiáng)制】表必備三字段: id , gmt _ create , gmt _ modified 。

    • 說(shuō)明:其中 id 必為主鍵,類型為 unsigned bigint 、單表時(shí)自增、步長(zhǎng)為 1。 gmt_create,
      gmt_modified 的類型均為 date_time 類型,前者現(xiàn)在時(shí)表示主動(dòng)創(chuàng)建,后者過(guò)去分詞表示被
      動(dòng)更新。
  • 【推薦】字段允許適當(dāng)冗余,以提高查詢性能,但必須考慮數(shù)據(jù)一致。冗余字段應(yīng)遵循:

    • 1 ) 不是頻繁修改的字段。
    • 2 ) 不是 varchar 超長(zhǎng)字段,更不能是 text 字段。
    • 正例:商品類目名稱使用頻率高,字段長(zhǎng)度短,名稱基本一成不變,可在相關(guān)聯(lián)的表中冗余存
      儲(chǔ)類目名稱,避免關(guān)聯(lián)查詢。

(二) 索引規(guī)約

  • 【強(qiáng)制】業(yè)務(wù)上具有唯一特性的字段,即使是多個(gè)字段的組合,也必須建成唯一索引。

  • 【強(qiáng)制】超過(guò)三個(gè)表禁止 join。需要 join 的字段,數(shù)據(jù)類型必須絕對(duì)一致;多表關(guān)聯(lián)查詢時(shí),
    保證被關(guān)聯(lián)的字段需要有索引。

  • 【強(qiáng)制】在 varchar 字段上建立索引時(shí),必須指定索引長(zhǎng)度,沒(méi)必要對(duì)全字段建立索引,根據(jù)
    實(shí)際文本區(qū)分度決定索引長(zhǎng)度即可。

  • 【強(qiáng)制】頁(yè)面搜索嚴(yán)禁左模糊或者全模糊,如果需要請(qǐng)走搜索引擎來(lái)解決。

  • 【推薦】利用覆蓋索引來(lái)進(jìn)行查詢操作,避免回表。說(shuō)明:如果一本書需要知道第 11 章是什么標(biāo)題,會(huì)翻開(kāi)第 11 章對(duì)應(yīng)的那一頁(yè)嗎?目錄瀏覽
    一下就好,這個(gè)目錄就是起到覆蓋索引的作用。

正例:能夠建立索引的種類:主鍵索引、唯一索引、普通索引,而覆蓋索引是一種查詢的一種
效果,用 explain 的結(jié)果,extra 列會(huì)出現(xiàn):using index。

  • 【推薦】建組合索引的時(shí)候,區(qū)分度最高的在最左邊。

正例:如果 where a=? and b=? ,a 列的幾乎接近于唯一值,那么只需要單建 idx_a 索引即
可。

(三) SQL語(yǔ)句

  • 【強(qiáng)制】不要使用 count(列名)或 count(常量)來(lái)替代 count(*),count(*)是 SQL92 定義的
    標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語(yǔ)法,跟數(shù)據(jù)庫(kù)無(wú)關(guān),跟 NULL 和非 NULL 無(wú)關(guān)。
  • 【強(qiáng)制】不得使用外鍵與級(jí)聯(lián),一切外鍵概念必須在應(yīng)用層解決。

    • 說(shuō)明:以學(xué)生和成績(jī)的關(guān)系為例,學(xué)生表中的 student _ id 是主鍵,那么成績(jī)表中的 student _ id則為外鍵。如果更新學(xué)生表中的 student _ id ,同時(shí)觸發(fā)成績(jī)表中的 student _ id 更新,即為級(jí)聯(lián)更新。外鍵與級(jí)聯(lián)更新適用于單機(jī)低并發(fā),不適合分布式、高并發(fā)集群 ; 級(jí)聯(lián)更新是強(qiáng)阻塞,存在數(shù)據(jù)庫(kù)更新風(fēng)暴的風(fēng)險(xiǎn) ; 外鍵影響數(shù)據(jù)庫(kù)的插入速度。
  • 【強(qiáng)制】禁止使用存儲(chǔ)過(guò)程,存儲(chǔ)過(guò)程難以調(diào)試和擴(kuò)展,更沒(méi)有移植性。

(四)ORM 映射

  • 【強(qiáng)制】在表查詢中,一律不要使用 * 作為查詢的字段列表,需要哪些字段必須明確寫明。

六、工程結(jié)構(gòu)

(一)應(yīng)用分層

在這里插入圖片描述

(二)二方庫(kù)依賴

(三)服務(wù)器

  • 【推薦】高并發(fā)服務(wù)器建議調(diào)小 TCP 協(xié)議的 time_ wait 超時(shí)時(shí)間。

    • 說(shuō)明:操作系統(tǒng)默認(rèn) 240 秒后,才會(huì)關(guān)閉處于 time_ wait 狀態(tài)的連接,在高并發(fā)訪問(wèn)下,服務(wù)器端會(huì)因?yàn)樘幱?time _ wait的連接數(shù)太多,可能無(wú)法建立新的連接,所以需要在服務(wù)器上調(diào)小此等待值。
    • 正例:在 linux 服務(wù)器上請(qǐng)通過(guò)變更/ etc / sysctl . conf 文件去修改該缺省值 ( 秒 ) :
      net . ipv 4. tcp _ fin _ timeout = 30
  • 【推薦】調(diào)大服務(wù)器所支持的最大文件句柄數(shù) (File Descriptor ,簡(jiǎn)寫為 fd) 。

    • 說(shuō)明:主流操作系統(tǒng)的設(shè)計(jì)是將 TCP / UDP 連接采用與文件一樣的方式去管理,即一個(gè)連接對(duì)
      應(yīng)于一個(gè) fd 。主流的 linux 服務(wù)器默認(rèn)所支持最大 fd 數(shù)量為 1024,當(dāng)并發(fā)連接數(shù)很大時(shí)很
      容易因?yàn)?fd 不足而出現(xiàn)“ open too many files ”錯(cuò)誤,導(dǎo)致新的連接無(wú)法建立。 建議將 linux
      服務(wù)器所支持的最大句柄數(shù)調(diào)高數(shù)倍 ( 與服務(wù)器的內(nèi)存數(shù)量相關(guān) ) 。
  • 【推薦】給 JVM 設(shè)置-XX:+HeapDumpOnOutOfMemoryError 參數(shù),讓 JVM 碰到 OOM 場(chǎng)景時(shí)輸出
    dump 信息。

  • 【推薦】在線上生產(chǎn)環(huán)境, JVM 的 Xms 和 Xmx 設(shè)置一樣大小的內(nèi)存容量,避免在 GC 后調(diào)整堆
    大小帶來(lái)的壓力。

  • 【參考】服務(wù)器內(nèi)部重定向使用 forward; 外部重定向地址使用 URL 拼裝工具類來(lái)生成,否則
    會(huì)帶來(lái) URL 維護(hù)不一致的問(wèn)題和潛在的安全風(fēng)險(xiǎn)。

關(guān)注我

我是蠻三刀把刀,目前為后臺(tái)開(kāi)發(fā)工程師。主要關(guān)注后臺(tái)開(kāi)發(fā),網(wǎng)絡(luò)安全,Python爬蟲(chóng)等技術(shù)。

來(lái)微信和我聊聊:yangzd1102

Github:https://github.com/qqxx6661

原創(chuàng)博客主要內(nèi)容

  • 筆試面試復(fù)習(xí)知識(shí)點(diǎn)手冊(cè)
  • Leetcode算法題解析(前150題)
  • 劍指offer算法題解析
  • Python爬蟲(chóng)相關(guān)技術(shù)分析和實(shí)戰(zhàn)
  • 后臺(tái)開(kāi)發(fā)相關(guān)技術(shù)分析和實(shí)戰(zhàn)

個(gè)人公眾號(hào):Rude3Knife

個(gè)人公眾號(hào):Rude3Knife

如果文章對(duì)你有幫助,不妨收藏起來(lái)并轉(zhuǎn)發(fā)給您的朋友們~

?著作權(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)容