頭圖 | CSDN 下載自東方 IC
作者 | sowhat1412 責編 | 張文
來源 | sowhat1412(ID:sowhat9094)
話不多說直接上乾貨,你我共勉。
構造器參數太多怎麼辦
解決辦法 :引入Builder 模式場景:當構造器有 5 個或者以上的構造參數時或者目前參數不多但是以後會不斷增多的時候。demo 如下:
調用的時候如下:
不需要實例化的類構造器要私有化
經常用到的 Utils 類,比如 Java 自帶的 java.util.Arrays 這樣的類,工具類都儘量不要實例化。
不要創建不必要對象
能用基本類型到時候儘量要用基本類型。比如我們做數字運算,如果定義稱了個 Long 類型,會涉及到==自動裝箱==。大大耗時。
對於一些程序中共用的參數儘量設置為 static 類型變量。
對於一些耗時性較大的對象比如數據庫連接,儘量創建數據庫連接池。
對於一些佔據內存較大的對象也儘量少創建。因為在 eden 區來回倒騰,它累啊!
耗時:7042ms
耗時:820ms
避免使用終結方法
4.1 finalze方法:
finalize() 是 Object 的 protected 方法,子類可以覆蓋該方法以實現==資源清理==工作,GC 在回收對象之前調用該方法。
finalize() 與 C++中的析構函數不是對應的,但 Java 中的 finalize 的調用具有==不確定性==。
finalize 方法在垃圾回收器準備垃圾回收前被調用,但是==不一定==會被調用
finalize() 其實是用來釋放==不是==通過 java 的 new 關鍵字分配的內存,比如說通過本地方法調用了 c 程序,該 c 程序 malloc 分配了內存,那麼垃圾回收器就不能通過 java 語言來釋放內存,只能在 finalize 方法內通過本地方法調用 c 程序進行釋放內存。
一個對象要被回收要經過一次標記可達法已經兩次 check 才算死亡。
總結來說:finalize() 並不是必須要執行的,它只能執行 1 次或者 0 次。如果在 finalize 中建立對象關聯,則當前對象可以復活 1 次。
4.2 System.gc
用 System.gc() 的時候,其實並不會馬上進行垃圾回收,甚至不一定會執行垃圾回收。查看 System.gc() 的源碼可以看到只有當 justRanFinalization=true 的時候系統才會真正 GC。如果真要回收查看源碼知道 System.gc() 要跟System.runFinalization() 一起搭配使用才好。
類跟成員的可訪問性最小化
這個說白了就是設計模式中的迪米特法則。定義:要求一個對象應該對其他對象有最少的瞭解,所以迪米特法則又叫做最少知識原則(Least Knowledge Principle, LKP)。
意義:迪米特法則的意義在於降低類之間的耦合。由於每個對象儘量減少對其他對象的瞭解,因此,很容易使得系統的功能模塊功能獨立,相互之間不存在(或很少有)依賴關係,日常最常見的比如成員變量私有化。
使可變性最小化
儘可能的使用 final 來修飾一些變量,這樣的化線程操作就不需要考慮同步問題,同時也對於一個變量不同 setX 方法也 OK。
優先使用複合勝過繼承
繼承是實現代碼重用的有力手段,但是使用不當會導致軟件變得脆弱。在包的內部使用繼承是非常安全的,子類和超類的實現都處在同一個程序員的控制之下。對於專門為了繼承而設計、並且具有很好的文檔說明的類來說,使用繼承也是非常安全的。然而們對於進行跨越包邊界的繼承,則要非常小心。“繼承”在這裡特指一個類擴展另一個類。需要我們對父類十分對了解才可繼承,只有當子類和超類之間==確實存在==父子關係時,才可以考慮使用繼承。否則都應該用複合,包裝類不僅比子類更加健壯,而且功能也更加強大。Effective Java
接口優於抽象類
簡而言之,Java 只允許單繼承但是允許實現多個接口。通過接口擴充方法很簡單,這樣也複合設計模式中的開閉原則。接口可以簡單的理解比抽象類還要抽象的一層,是我們對外提供的接口。同時這裡提一下==骨架抽象類==。
骨架類存在的意義是實現一個接口中設計者認為比較公用的方法,然後在具體類實現的時候,具體類繼承自骨架類同時實現接口類的若幹方法。
HashSet 源碼
看 Set 源碼
AbstractSet 源碼
AbstractSet 抽象類有若幹函數已經實現了。
HashSet 實現了 Set的接口,同時它還繼承自 AbstractSet這個骨架類(類中有一些公用方法)
可變參數謹慎使用
JDK5 增加了可變參數方法(variable arity method),可變參數方法接受 0 個或多個指定類型的參數。
可變參數機制:先創建一個數組,數組大小為調用位置所傳遞的參數數量,然後將參數值傳遞到數組中,最後將數組傳遞給方法。弊端如下:
如果所傳參數為 null,方法裡有對參數的引用(比如 args[0])時,那麼就會在運行時失敗(編譯時卻檢測不出錯誤);
在對性能有要求時,我們要慎重考慮是否使用可變參數。因為,可變參數方法的調用都會引起 array 的內存分配和初始化,這會給性能帶來損耗。
當可變參數的使用發生變動時(比如:以前用可變參數方法,現在用普通方法),所有引用參數列表的類的 .class 都要重新生成,因為可變參數的 array 的分配和初始化是在編譯期間完成的。
Effective Java 給我們的建議是:假設調用可變參數的方法中,有 95%只是調用參數個數小於 4,那麼就可以將個數小於 4 的方法,用普通方法定義;剩餘的 5%,調用可變參數方法。
儘量不要返回NULL,儘量返回零數組或集合
函數中如果返回 NULL,那麼代碼還要去重新判斷返回值。JDK 都主動給我們提供好了Collections.EMPTY_LIST。當然如果是對象就只能是 NULL 了另當別論。阿裡巴巴開發手冊也是這樣建議的哦。
返回值為 null 並不會有什麼問題,但是在“解引用”(dereference)時,調用者沒有對 null 進行判斷就會出現 NullPointerException。
在返回值為數組或者集合時,儘量返回長度為零的數組或者集合,而不是null,這樣在調用時就能簡化代碼,減少不必要的麻煩,並且不必擔心NullPointer 異常(除非這對性能會造成很大的影響)。
優先使用標準異常
總結來說好處就是:追求代碼的重用考慮,在裝載類的性能上面考慮。具體細節如下:
它使你對官方 API 更加易於學習和使用,因為他與程序員已經熟悉的習慣用法是一致的。
對於用到這些 API 的程序而言,他們的可讀性會更好,因為他們不會出現很多程序員不熟悉的異常。
異常類越少,意味著內存印跡就越小,裝載這些類的時間開銷也越少。
儘量使用枚舉替換 int
枚舉的本質就是一個類的具體實例。枚舉比普通業務類型 int 類型的區別跟好處,以及策略枚舉的使用,這些以前寫給直接看==>花樣玩枚舉。
局部變量作用域最小化
從系統 GC 的角度考慮(一個變量的週期越短整個 gc 過程越快);
從棧楨中的局部變量表的可重用性來看,作用域越小系統的棧楨空間利用了越大;
可以增強代碼的可讀性和可維護性,並降低出錯的可能性。
應該:
在第一次使用某個局部變量的地方進行聲明。
如果你還沒有足夠的前置信息來對一個變量進行有意義的初始化,就應該推遲這個聲明,直到可以初始化為止。
儘量將方法小而集中。方法的功能儘量單一。
對於精度技術不用 float 或 double
Java 在允許 float 或者 double 類之間計算的時候會有誤差。
要用:BigDecimal 或者 FloatDecimal。具體類用法自行百度。
字符串操作少用 String
這點操作是大家都知道的,String 定義為 private final byte[] value 是不可變的。StringBuilder 和 StringBuffer 都繼承於:AbstractStringBuilder 。他們的底層使用的是沒有用 final 修飾的字符數組:char[]
如果要操作少量的數據用 String;
多線程操作字符串緩衝區下操作大量數據 StringBuffer;
單線程操作字符串緩衝區下操作大量數據 StringBuilder。
對資源的 close 建議分開操作
比如說我們有這樣的一個 close 方法,
上面這樣寫一旦 a 關閉的時候出錯了,b 的關閉也會出錯。儘量分開來關閉。
數據類型轉換
基本數據類型轉換為 String 的時候注意性能優化,比如 Integer 類型數據轉換為String 一般有三種方法:
Integer.toString 方法,首先推薦。速度最好
String.valueOf() ,該方法底層調用的是 Integer.toString 方法,速度中等。
i + "" 這種方法,底層是用 StringBuilder 實現,先用 append 方法拼接,再用 toString 方法獲取字符串。速度最慢。
不用的對象記得置 NULL
我們不用一個空間對象後而沒有將其置 NULL,JDK 底層代碼對用不到的對象都會立馬置空,如果不這樣容易造成內存洩露,比如我自己實現了一個棧
if 判斷常量在前
if(i==1) 跟 if(1==i)看起來沒有差別,但是從容錯性上面來考慮,如果手誤寫成了 if(i=1)就是賦值語句了,而 if(1=i)則不會出現這樣的錯誤。因此 if 判斷建議常量在前,變量在後。
字符串變量比較的時候
str.equal("sowhat") 跟 “sowhat”.equal(str)功能上看是一樣的,但是從代碼的健壯性來看推薦後者,因為你無法確實 str 一定是非空,可以避免空指針異常。
同步方法跟同步方法塊
儘量使用同步方法塊而不是同步方法,這點在多線程模塊中的 synchronized 鎖 方法塊文章中已經講得很清楚了,除非我們能確定一整個方法都是需要進行同步的,否則儘量使用同步代碼塊,避免對那些不需要進行同步的代碼也進行了同步,影響了代碼執行效率。
方法要儘可能小
一個方法要儘量實現單一指責,方法編譯後字節碼越小越可能會引發 JIT 的方法內聯,
一定記得寫註釋
代碼寫的再好也要記得寫類跟方法的大概註釋,不然接收你工作的人絕對分分鐘化身祖安玩家!
以上。
轉載請超鏈接註明:頭條資訊 » 寫好規範 Java 代碼去大廠!
免責聲明 :非本網註明原創的信息,皆為程序自動獲取互聯網,目的在於傳遞更多信息,並不代表本網贊同其觀點和對其真實性負責;如此頁面有侵犯到您的權益,請給站長發送郵件,並提供相關證明(版權證明、身份證正反面、侵權鏈接),站長將在收到郵件24小時內刪除。