Java做爲一門名副其實的工業級語言,語法友好,學習簡單,大規模的應用給代碼質量的管控帶來了困難,特別是團隊開發中,開發過程當中的規範會直接影響最終項目的穩定性。java
善醫者「未有形而除之」,提升工程健壯性最好的方式是在代碼出現問題以前就排除掉,不給Bug出現的機會。一份好的開發規範就能夠起到這樣的做用,大大減小產品上線後的問題。linux
《阿里巴巴Java開發手冊》是阿里巴巴的內部編碼規範,阿里官方的Java代碼規範標準, 手冊以Java應用開發爲維度,分爲編程規約、異常日誌規約、MYSQL規約、工程規約、安全規約五個章節,給出了強制、推薦、參考三個級別,每條規範都有推薦的約束力度,從命名到項目拆分,不只規範了一些開發細節,也提出了不少工程開發的哲學,值得好好閱讀。數據庫
點擊下載《阿里巴巴Java開發手冊》(v1.1.0版)編程
下面記錄一些對我比較有啓發的條款,提綱挈領,快速學習,方便尚未閱讀的同窗快速瞭解。設計模式
將設計模式體如今名字中,有利於閱讀者快速理解架構設計思想。 api
可變參數必須放置在參數列表的最後,儘可能不用可變參數編程。數組
接口過期必須加@Deprecated 註解,並清晰地說明採用的新接口或者新服務是什麼。緩存
1) 全部的POJO類屬性必須使用包裝數據類型安全
2) RPC方法的返回值和參數必須使用包裝數據類型性能優化
3) 全部的局部變量【推薦】使用基本數據類型
POJO 類屬性沒有初值是醒使用者在須要使用時,必須本身顯式地進行賦值,任何 NPE 問題,或者入庫檢查,都由使用者來保證。數據庫的查詢結果多是null,由於自動拆箱,用基本數據類型接收有NPE風險。
序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失敗;若是徹底不兼容升級,避免反序列化混亂,那麼請修改 serialVersionUID 值。
使用 IDE 的中工具:source> generate toString 時,若是繼承了另外一個 POJO 類,注意在前面加一下 super.toString。 在方法執行拋出異常時,能夠直接調用 POJO 的 toString()方法打印其屬性值,便於排查問題。
1) 不須要從新賦值的變量,包括類屬性、局部變量
2) 對象參數前加final,表示不容許修改引用的指向
3) 類方法肯定不容許被重寫
對象的 clone 方法默認是淺拷貝,若想實現深拷貝須要重寫 clone 方法實現屬性對象 的拷貝。
1) 若是不容許外部直接經過new來建立對象,那麼構造方法必須是private
2) 工具類不容許有public或default構造方法
3) 類非static成員變量而且與子類共享,必須是protected 4) 類非static成員變量而且僅在本類使用,必須是private
5) 類static成員變量若是僅在本類使用,必須是private
6) 如果static成員變量,必須考慮是否爲final
7) 類成員方法只供類內部調用,必須是private
8) 類成員方法只對繼承類公開,那麼限制爲protected
任何類、方法、參數、變量,嚴控訪問範圍。過寬泛的訪問範圍,不利於模塊解耦。思考:若是是一個 private 的方法,想刪除就刪除,但是一個 public 的 Service 方法,或者一個 public 的成員變量,刪除一下,不得手心冒點汗嗎?變量像本身的小孩,儘可能在本身的視線內,變量做用域太大,若是無限制的處處跑,那麼你會擔憂的。
subList 返回的是 ArrayList 的內部類 SubList,並非 ArrayList ,而是 ArrayList 的一個視圖,對於SubList子列表的全部操做最終會反映到原列表上。
使用add/remove/clear 方法會拋出 UnsupportedOperationException 異常。asList 的返回對象是一個 Arrays 內部類,並無實現集合的修改方法。Arrays.asList體現的是適配器模式,只是轉換接口,後臺的數據還是數組。
remove 元素請使用 Iterator方式,若是併發操做,須要對 Iterator 對象加鎖。
資源驅動類、工具類、單例工廠類都須要注意。
這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。 Executors 返回的線程池對象的弊端以下: 1)FixedThreadPool 和 SingleThreadPool:
容許的請求隊列長度爲 Integer.MAX_VALUE,可能會堆積大量的請求,從而致使 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
容許的建立線程數量爲 Integer.MAX_VALUE,可能會建立大量的線程,從而致使 OOM。
若是定義爲static,必須加鎖,或者使用 DateUtils 工具類。 注意線程安全,使用 DateUtils。亦推薦以下處理:
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } };
能用無鎖數據結構,就不要用鎖;能鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。
要麼在應用層加鎖,要麼在緩存加鎖,要麼在 數據庫層使用樂觀鎖,使用 version 做爲更新依據。 若是每次訪問衝突機率小於 20%,推薦使用樂觀鎖,不然使用悲觀鎖。樂觀鎖的重試次數不得小於 3 次。
方法,線程執行代碼注意 catch 異常,確保 countDown 方法能夠執行,避免主線程沒法執行 至 await 方法,直到超時才返回結果。注意,子線程拋出異常堆棧,不能在主線程 try-catch 到。
Random 實例包括 java.util.Random 的實例或者 Math.random()實例。
對於一寫多讀,是能夠解決變量同步問題, 可是若是多寫,一樣沒法解決線程安全問題。若是是 count++操做,使用以下類實現: AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 若是是 JDK8,推薦使用 LongAdder 對象,比 AtomicLong 性能更好(減小樂觀鎖的重試次數)。
這個變量是針對一個線程內全部操做共有的,因此設置爲靜態變量,全部此類實例共享 此靜態變量 ,也就是說在類第一次被使用時裝載,只分配一塊存儲空間,全部此類的對象(只要是這個線程內定義的)均可以操控這個變量。
catch 時請分清穩定代碼和非穩 定代碼,穩定代碼指的是不管如何不會出錯的代碼。對於非穩定代碼的catch儘量進行區分 異常類型,再作對應的異常處理。
若是不想處理它,請將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化爲用戶能夠理解的內容。
對於公司外的 http/api 開放接口必須 使用「錯誤碼」;而應用內部推薦異常拋出;跨應用間 RPC 調用優先考慮使用 Result 方式,封 裝 isSuccess、「錯誤碼」、「錯誤簡短信息」。
隨意複製和粘貼代碼,必然會致使代碼的重複,在之後須要修改時,須要修改全部的副本,容易遺漏。
式
若是不處理,那麼往上拋。
float 和 double 在存儲的時候,存在精度損失的問題,極可能在值的比較時,獲得不正確的結果。若是存儲的數據範圍超過 decimal 的範圍,建議將數據拆成整數和小數分開存儲。
其中id必爲主鍵,類型爲unsigned bigint、單表時自增、步長爲1。gmtcreate, gmtmodified 的類型均爲 date_time 類型。
若是預計三年後的數據量根本達不到這個級別,請不要在建立表時就分庫分表。避免過分設計。
不必對全字段創建索引,根據實際文本區分度決定索引長度。 說索引的長度與區分度是一對矛盾體,通常對字符串類型數據,長度爲 20 的索引,區分 度會高達 90%以上,可使用 count(distinct left(列名, 索引長度))/count(*)的區分度 來肯定。
可以創建索引的種類:主鍵索引、惟一索引、普通索引,而覆蓋索引是一種查詢的一種 效果,用explain的結果,extra列會出現:using index。若是索引包含全部知足查詢須要的數據的索引成爲覆蓋索引(Covering Index),也就是平時所說的不須要回表操做
MySQL 並非跳過 offset 行,而是取 offset+N 行,而後返回放棄前 offset 行,返回 N 行,那當 offset 特別大的時候,效率就很是的低下,要麼控制返回的總頁數,要麼對超過特定閾值的頁數進行 SQL 改寫。
至少要達到 range 級別,要求是 ref 級別,若是能夠是 consts 最好。
1)consts 單表中最多隻有一個匹配行(主鍵或者惟一索引),在優化階段便可讀取到數據。 2)ref 指的是使用普通的索引(normal index)。 3)range 對索引進行範圍檢索。
count()就是 SQL92 定義 的標準統計行數的語法,跟數據庫無關,跟 NULL 和非 NULL 無關。 count()會統計值爲 NULL 的行,而 count(列名)不會統計此列爲 NULL 值的行。
注意,NULL與任何值的直接比較都爲 NULL
外鍵與級聯更新適用於單機低併發,不適合分佈式、高併發集羣;級聯更新是強阻塞,存在數據庫更新風暴的風險;外鍵影響數據庫的插入速度。
其實現方式是在數據庫取到 statementName 對應的 SQL 語句的全部記錄,再經過 subList 取 start,size 的子集合,線上由於這個緣由曾經出現過 OOM。
傳入爲 POJO 類,無論是否是本身的目標更新字段, 都進行 update table set c1=value1,c2=value2,c3=value3; 這是不對的。
執行 SQL 時,儘可能不要更新無改動的字段,一是易出錯;二是效率低;三是 binlog 增長存儲。
操做系統默認 240 秒後,纔會關閉處於 timewait 狀態的鏈接,在高併發訪問下,服 務器端會由於處於 timewait 的鏈接數太多,可能沒法創建新的鏈接,因此須要在服務器上 調小此等待值。 正例:在 linux 服務器上請經過變動/etc/sysctl.conf 文件去修改該缺省值(秒): net.ipv4.tcpfintimeout = 30
主流操做系統的設計是將 TCP/UDP 鏈接採用與文件同樣的方式去管理,即一個鏈接對應於一個 fd。主流的 linux 服務器默認所支持最大 fd 數量爲 1024,當併發鏈接數很大時很 容易由於 fd 不足而出現「open too many files」錯誤,致使新的鏈接沒法創建。 建議將 linux 服務器所支持的最大句柄數調高數倍(與服務器的內存數量相關)。
防止沒有作水平權限校驗就可隨意訪問、操道別人的數據,好比查看、修改別人的訂單。
查看我的手機號碼會顯示成:158****9119,隱藏中間 4 位,防止隱私泄露。
忽略參數校驗可能致使: page size過大致使內存溢出 惡意order by致使數據庫慢查詢 任意重定向 SQL注入 反序列化注入 正則輸入源串拒絕服務ReDoS——Java 代碼用正則來驗證客戶端的輸入,有些正則寫法驗證普通用戶輸入沒有問題, 可是若是攻擊人員使用的是特殊構造的字符串來驗證,有可能致使死循環的效果。
CSRF(Cross-site request forgery)跨站請求僞造是一類常見編程漏洞。對於存在 CSRF 漏洞的應用/網站,攻擊者能夠事先構造好 URL,只要受害者用戶一訪問,後臺便在用戶 不知情狀況下對數據庫中用戶參數進行相應修改。
如註冊時發送驗證碼到手機,若是沒有限制次數和頻率,那麼能夠利用此功能騷擾到其 它用戶,並形成短信平臺資源浪費。