阿里巴巴Java開發手冊閱讀筆記 [復制鏈接]

2019-11-8 11:47
shareiOS 閱讀:355 評論:0 贊:0
Tag:  阿里巴巴 Java

一、編程規約

(一)命名風格

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

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

  • 【推薦】如果模塊、接口、類、方法使用了設計模式,在命名時體現出具體模式。

public class OrderFactory;

public class LoginProxy;

public class ResourceObserver;

(二)常量定義

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

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

cache.put(key, value);

  • 【推薦】如果變量值僅在一個范圍內變化,且帶有名稱之外的延伸屬性,定義為枚舉類。

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

(三)代碼格式

(四)OOP 規約

  • 【強制】避免通過一個類的對象引用訪問此類的靜態變量或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可。
  • 【強制】外部正在調用或者二方庫依賴的接口,不允許修改方法簽名,避免對接口調用方產生影響。接口過時必須加@Deprecated 注解,并清晰地說明采用的新接口或者新服務是什么。
  • 【強制】所有的相同類型的包裝類對象之間值的比較,全部使用 equals 方法比較。

說明:對于 Integer var = ? 在-128 至 127 范圍內的賦值,Integer 對象是在IntegerCache.cache 產生,會復用已有對象,這個區間內的 Integer值可以直接使用==進行判斷,但是這個區間之外的所有數據,都會在堆上產生,并不會復用已有對象,這是一個大坑,推薦使用 equals 方法進行判斷。

  • 【強制】序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失敗;如果完全不兼容升級,避免反序列化混亂,那么請修改 serialVersionUID 值。

說明:注意 serialVersionUID 不一致會拋出序列化運行時異常。

  • 【強制】構造方法里面禁止加入任何業務邏輯,如果有初始化邏輯,請放在 init 方法中。
  • 【強制】POJO 類必須寫 toString 方法。使用 IDE 的中工具:source> generate toString
    時,如果繼承了另一個 POJO 類,注意在前面加一下 super.toString。

說明:在方法執行拋出異常時,可以直接調用 POJO 的 toString()方法打印其屬性值,便于排
查問題。

  • 【推薦】循環體內,字符串的連接方式,使用 StringBuilder 的 append 方法進行擴展。

說明:反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,然后進行
append 操作,最后通過 toString 方法返回 String 對象,造成內存資源浪費。

反例:

(五)集合處理

  • 【強制】關于 hashCode 和 equals 的處理,遵循如下規則: 1) 只要重寫 equals,就必須重寫 hashCode。 2) 因為 Set 存儲的是不重復的對象,依據 hashCode 和 equals 進行判斷,所以 Set 存儲的對象必須重寫這兩個方法。 3) 如果自定義對象做為 Map 的鍵,那么必須重寫 hashCode 和 equals。

說明:String 重寫了 hashCode 和 equals 方法,所以我們可以非常愉快地使用 String 對象
作為 key 來使用。

  • 【強制】ArrayList的subList結果不可強轉成ArrayList,否則會拋出ClassCastException
    異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.

說明:subList 返回的是 ArrayList 的內部類 SubList,并不是 ArrayList ,而是
ArrayList 的一個視圖,對于 SubList 子列表的所有操作最終會反映到原列表上。

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

反例:直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強轉其它
類型數組將出現 ClassCastException 錯誤。

  • 【強制】使用工具類Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方法,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。

說明:asList 的返回對象是一個 Arrays 內部類,并沒有實現集合的修改方法。Arrays.asList
體現的是適配器模式,只是轉換接口,后臺的數據仍是數組。
String[] str = new String[] { "you", "wu" };
List list = Arrays.asList(str);

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

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

  • 【強制】不要在 foreach 循環里進行元素的 remove/add 操作。remove 元素請使用 Iterator方式,如果并發操作,需要對 Iterator 對象加鎖。
  • 【推薦】高度注意 Map 類集合 K/V 能不能存儲 null 值的情況,如下表格:

在這里插入圖片描述

(六)并發處理

  • 【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式創建線程。

說明:使用線程池的好處是減少在創建和銷毀線程上所花的時間以及系統資源的開銷,解決資
源不足的問題。如果不使用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或者
“過度切換”的問題。

  • 【強制】線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
  • 【推薦】避免 Random 實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一seed 導致的性能下降。

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

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

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

(七)控制語句

  • 【推薦】表達異常的分支時,少用 if-else 方式

說明:如果非得使用 if()…else if()…else…方式表達邏輯,【強制】避免后續代碼維
護困難,請勿超過 3 層。
正例:超過 3 層的 if-else 的邏輯判斷代碼可以使用衛語句、策略模式、狀態模式等來實現,
其中衛語句示例如下:

(八)注釋規約

(九)其它

  • 【強制】在使用正則表達式時,利用好其預編譯功能,可以有效加快正則匹配速度。
  • 【強制】后臺輸送給頁面的變量必須加$!{var}——中間的感嘆號。

說明:如果 var=null 或者不存在,那么${var}會直接顯示在頁面上。

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

二、異常日志

(一)異常處理

  • 【強制】Java 類庫中定義的一類 RuntimeException 可以通過預先檢查進行規避,而不應該 通過 catch 來處理,比如:IndexOutOfBoundsException,NullPointerException 等等。

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

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

  • 【強制】異常不要用來做流程控制,條件控制,因為異常的處理效率比條件分支低。
  • 【強制】對大段代碼進行 try-catch,這是不負責任的表現
  • 【強制】捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請
    將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化為用戶可以理解的
    內容。
  • 【推薦】防止 NPE,是程序員的基本修養.
  • 【參考】在代碼中使用“拋異常”還是“返回錯誤碼”,對于公司外的 http/api 開放接口必須
    使用“錯誤碼”;而應用內部推薦異常拋出;跨應用間 RPC 調用優先考慮使用 Result 方式,封
    裝 isSuccess()方法、“錯誤碼”、“錯誤簡短信息”

(二)日志規約

  • 【強制】日志文件推薦至少保存 15 天,因為有些異常具備以“周”為頻次發生的特點。
  • 【強制】應用中不可直接使用日志系統(Log4j、Logback)中的 API,而應依賴使用日志框架SLF4J中的API,使用門面模式的日志框架,有利于維護和各個類的日志處理方式統一。

三、單元測試

  • 【強制】好的單元測試必須遵守 AIR 原則。 說明:單元測試在線上運行時,感覺像空氣(AIR)一樣并不存在,但在測試質量的保障上, 卻是非常關鍵的。好的單元測試宏觀上來說,具有自動化、獨立性、可重復執行的特點。 A:Automatic(自動化) I:Independent(獨立性) R:Repeatable(可重復)

四、安全規約

  • 【強制】隸屬于用戶個人的頁面或者功能必須進行權限控制校驗。
  • 【強制】用戶輸入的 SQL 參數嚴格使用參數綁定或者 METADATA 字段值限定,防止 SQL 注入,
    禁止字符串拼接 SQL 訪問數據庫。
  • 【強制】用戶請求傳入的任何參數必須做有效性驗證。

五、MySQL 數據庫

(一) 建表規約

  • 【強制】如果存儲的字符串長度幾乎相等,使用 char 定長字符串類型。
  • 【強制】表達是與否概念的字段,必須使用 is _ xxx 的方式命名,數據類型是 unsigned tinyint( 1 表示是,0 表示否 ) 說明:任何字段如果為非負數,必須是 unsigned 。 正例:表達邏輯刪除的字段名 is_deleted ,1 表示刪除,0 表示未刪除。
  • 【強制】 varchar 是可變長字符串,不預先分配存儲空間,長度不要超過 5000,如果存儲長
    度大于此值,定義字段類型為 text ,獨立出來一張表,用主鍵來對應,避免影響其它字段索
    引效率。
  • 【強制】表必備三字段: id , gmt _ create , gmt _ modified 。 說明:其中 id 必為主鍵,類型為 unsigned bigint 、單表時自增、步長為 1。 gmt_create,
    gmt_modified 的類型均為 date_time 類型,前者現在時表示主動創建,后者過去分詞表示被
    動更新。
  • 【推薦】字段允許適當冗余,以提高查詢性能,但必須考慮數據一致。冗余字段應遵循: 1 ) 不是頻繁修改的字段。 2 ) 不是 varchar 超長字段,更不能是 text 字段。 正例:商品類目名稱使用頻率高,字段長度短,名稱基本一成不變,可在相關聯的表中冗余存
    儲類目名稱,避免關聯查詢。

(二) 索引規約

  • 【強制】業務上具有唯一特性的字段,即使是多個字段的組合,也必須建成唯一索引。
  • 【強制】超過三個表禁止 join。需要 join 的字段,數據類型必須絕對一致;多表關聯查詢時,
    保證被關聯的字段需要有索引。
  • 【強制】在 varchar 字段上建立索引時,必須指定索引長度,沒必要對全字段建立索引,根據
    實際文本區分度決定索引長度即可。
  • 【強制】頁面搜索嚴禁左模糊或者全模糊,如果需要請走搜索引擎來解決。
  • 【推薦】利用覆蓋索引來進行查詢操作,避免回表。說明:如果一本書需要知道第 11 章是什么標題,會翻開第 11 章對應的那一頁嗎?目錄瀏覽
    一下就好,這個目錄就是起到覆蓋索引的作用。

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

  • 【推薦】建組合索引的時候,區分度最高的在最左邊。

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

(三) SQL語句

  • 【強制】不要使用 count(列名)或 count(常量)來替代 count(*),count(*)是 SQL92 定義的
    標準統計行數的語法,跟數據庫無關,跟 NULL 和非 NULL 無關。
  • 【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。 說明:以學生和成績的關系為例,學生表中的 student _ id 是主鍵,那么成績表中的 student _ id則為外鍵。如果更新學生表中的 student _ id ,同時觸發成績表中的 student _ id 更新,即為級聯更新。外鍵與級聯更新適用于單機低并發,不適合分布式、高并發集群 ; 級聯更新是強阻塞,存在數據庫更新風暴的風險 ; 外鍵影響數據庫的插入速度。
  • 【強制】禁止使用存儲過程,存儲過程難以調試和擴展,更沒有移植性。

(四)ORM 映射

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

六、工程結構

(一)應用分層

阿里巴巴Java開發手冊閱讀筆記

在這里插入圖片描述

(二)二方庫依賴

(三)服務器

  • 【推薦】高并發服務器建議調小 TCP 協議的 time_ wait 超時時間。 說明:操作系統默認 240 秒后,才會關閉處于 time_ wait 狀態的連接,在高并發訪問下,服務器端會因為處于 time _ wait的連接數太多,可能無法建立新的連接,所以需要在服務器上調小此等待值。 正例:在 linux 服務器上請通過變更/ etc / sysctl . conf 文件去修改該缺省值 ( 秒 ) :
    net . ipv 4. tcp _ fin _ timeout = 30
  • 【推薦】調大服務器所支持的最大文件句柄數 (File Descriptor ,簡寫為 fd) 。 說明:主流操作系統的設計是將 TCP / UDP 連接采用與文件一樣的方式去管理,即一個連接對
    應于一個 fd 。主流的 linux 服務器默認所支持最大 fd 數量為 1024,當并發連接數很大時很
    容易因為 fd 不足而出現“ open too many files ”錯誤,導致新的連接無法建立。 建議將 linux
    服務器所支持的最大句柄數調高數倍 ( 與服務器的內存數量相關 ) 。
  • 【推薦】給 JVM 設置-XX:+HeapDumpOnOutOfMemoryError 參數,讓 JVM 碰到 OOM 場景時輸出
    dump 信息。
  • 【推薦】在線上生產環境, JVM 的 Xms 和 Xmx 設置一樣大小的內存容量,避免在 GC 后調整堆
    大小帶來的壓力。
  • 【參考】服務器內部重定向使用 forward; 外部重定向地址使用 URL 拼裝工具類來生成,否則
    會帶來 URL 維護不一致的問題和潛在的安全風險。

我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

龙江福彩p62开奖 在国外开服装厂赚钱吗 博定宝彩票游戏 代练怎样可以更赚钱 卖房子比上市公司赚钱 十块钱三样摆摊赚不赚钱 自己开个装修公司赚钱吗 电脑试玩应用赚钱是真的吗 600万彩票首页 手机看广告赚钱是真的吗 1+2棋牌捕鱼游戏 黑龙江承包农场赚钱吗 下载免费单机捕鱼达人 高中如何通过编程赚钱 528千炮捕鱼 投资光伏发电项目能赚钱吗 大玩家彩票网址