Java陣列/集合效能優化
1、 複製陣列元素,使用
System類arraycopy()
方法替代迴圈賦值在陣列之間複製元素
建議:System類arraycopy()方法複製陣列元素
杜絕:迴圈賦值複製陣列元素
原因: System類arraycopy()方法呼叫作業系統更底層函式,效率更高。
注:通過實測,在元素數量達到億級別,兩者都在幾百毫秒,都很快,System類arraycopy()比迴圈賦值效能僅快1倍,但仍推薦使用System類arraycopy()。
2、避免建立集合不設定初始容量
使用集合(List、Set、Map)儲存大量的物件
建議:先估計儲存的元素個數,然後在建立集合時設定集合的容量值要大於估計的元素個數。
杜絕:未設定集合容量值
原因:建立集合物件,如果未設定集合初始容量值,則使用預設值,而預設值都很小(如,ArrayList的初始容量為10),一旦儲存的元素個數超過閾值,會造成集合擴容。擴容方式是根據擴容因子建立一個新的集合物件(初始容量=原有集合容量*擴容因子),再將原有集合中的元素拷貝到新的集合中。如果產生多次擴容,則會產生很多無用的中間集合物件,以及多次無意義的元素拷貝,效能低下。
正確示例: 估計儲存的元素個數最大為10000,使用ArrayList集合
List list = new ArrayList(10000);
3、遍歷集合,使用迭代器替代迴圈呼叫帶索引的get方法
遍歷集合
建議:使用迭代器遍歷集合
杜絕:迴圈呼叫帶索引的get方法
原因:迭代器維護了遍歷集合的“指標”及內部狀態,它知道如何高效的遍歷集合。而集合提供的帶索引的get方法,對某些集合而言查詢索引需要從第一個元素開始遍歷(如LinkedList),效率非常低下。
注:雖然迭代器遍歷某些特定集合效能並非最優,例如,遍歷ArrayList,使用迴圈呼叫帶索引的get方法就比迭代器效能略高一些,但是絕大多數情況下迭代器遍歷集合都是最優的。對LinkedList,帶索引的get方法要從第一個元素開始查詢,使用迴圈呼叫帶索引的get方法遍歷效率非常低。
正確示例:
List list =…
Iterator it = list.iterator();
while(it.hasNext())
{
it.next()
}
錯誤示例:
List list =…
for(int i=0; i< list.size(); i++)
{
list.get(i)
}
4、單執行緒使用HashMap/ArrayList集合,避免使用HashTable/Vector
單執行緒使用集合
建議:HashMap/ArrayList
杜絕:HashTable/Vector
原因:HashMap/ArrayList是執行緒非安全的,元素的增加、刪除、查詢未實現同步,沒有鎖的申請和釋放開銷。而HashTable/Vector是執行緒安全的,元素的增加、刪除、查詢實現同步,存在鎖的申請和釋放開銷。
5、判斷元素是否在集合中存在,使用
HashSet/HashMap
替代List
判斷元素是否在集合中存在
建議:HashSet/HashMap
杜絕:List
原因:使用List集合儲存元素,則需要比較List集合中的所有元素,才能判斷查詢的元素是否在集合中存在。
使用HashSet/HashMap儲存元素,HashSet/HashMap會將所有元素或Key按hash值分桶儲存。通過查詢的元素或Key的hash值可快速找到其所在的桶,此步效率非常高(接近於陣列的下標查詢元素),然後只需比較桶上的元素即可判斷元素是否在集合存在,比較次數大大降低。