1. 程式人生 > >Android學習之——優化篇(1)

Android學習之——優化篇(1)

androi static 實用 mod 簡單 keys 階段 數據 秒級

一、優化的品質

1.簡練。2.可讀性強。3.模塊化;4.層次性;5.設計良好。6.高效。7.優雅;8.清晰。

二、常見的編程規範

1. 基本要求

· 結構清晰,簡單易懂。單個函數不超過100行。目標明白,代碼精簡

· 盡量使用標準庫函數和公共函數

· 不任意定義全局變量。盡量使用局部變量

· 使用括號。以避免二義性

2. 可讀性要求

· 可讀性第一,效率第二

· 保證凝視與代碼全然一致

· 都有文件頭說明,都有函數頭說明

· 定義變量時,凝視能反映含義;常量定義有說明

· 處理過程每一個階段都有凝視說明;典型算法亦是如此

· 使用縮進;循環,分支不超過5層

· 空白行也是一種特殊的凝視;一目了然的語句不加凝視

3. 結構化要求

· 禁止出現兩條等價的支路;用case實現多路分支

· 避免從循環引出多個出口;函數僅僅有一個出口

· 不要用條件賦值語句;避免不必要的分支;不要輕易用條件分支去替換邏輯表達式

4. 正確性與容錯性要求

· 首先保證正確。其次才是優美

· 時刻回頭檢查。改動前考慮對其它程序的影響

· 變量調用前必須被初始化

· 對用戶輸入進行合法性檢查

· 不要比較浮點數的相等,如:10.0*0.1 == 1.0

· 主動處理程序與環境狀態的關系,如:打印機是否聯機,文件是否能邏輯鎖定

· 做單元測試

5. 可重用性要求

· 反復使用的完畢相對獨立功能的算法或代碼應抽象為公共控件或類

· 公共空間或類應考慮面向對象思想。降低外界聯系。考慮獨立性或封裝性

三、程序性能測試

1. 計算性能

Java提供了 System.currentTimeMillis()方法,能夠得到毫秒級的當前時間,通過該方法來計算運行某一段代碼所消耗的時間。

我們能夠通過 Java的 java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler 利用動態代理來解決枯燥的輸入System.currentTimeMillis() 來計算運行時間的問題。

能夠參考該樣例:http://www.iteye.com/topic/683613

2. 內存消耗

利用 Runtime 類的freeMemory() 和 totalMemory() 方法來考慮程序中的對象所消耗的虛擬機堆空間

參考鏈接:http://blog.csdn.net/wgw335363240/article/details/8878644

3. 啟動時間

4. 可伸縮性

5. 用戶察覺性能


四、 0基礎優化

在 Java 程序中 性能問題大部分原因並不在於 Java 語言,而是在程序本身。養成好的代碼編寫習慣很重要。

1. 盡量指定類的 final 修飾符

帶有final修飾符的類不可派生。

假設指定一個類為 final 。則該類全部的方法都是 final 。

Java 編譯器會尋找機會內聯 (inline) 全部的 final 方法。此舉能使性能平均提高 50%。

2. 盡量重用對象

特別是 String 對象的使用中,出現字符串連接情況應用 StringBuffer 取代。

3. 盡量使用局部變量

調用方法時傳遞的參數以及在調用中創建的暫時變量都保存在棧(Stack)中。速度較快。

其它的都保存在堆(Heap)中。速度較慢。

4. 不要反復初始化變量

默認情況下。調用類的構造函數時,Java 會把變量初始化成確定的值,全部的對象被設置成 null,整數變量設置為 0。float 和 double 為 0.0。邏輯為 false。當一個類從還有一個類派生時。尤為要註意,由於用 new 關鍵詞創建一個對象時,構造函數鏈中的全部構造函數都會被自己主動調用。

5. Java + Oracle 的應用開發中, Java內嵌的SQL語句使用大寫

6. Java 編譯過程中,數據庫連接、I/O 流操作要及時關閉釋放

7. 對象使用完成後,手動設置為 null

8. 在使用同步機制時,應盡量用法同步取代代碼塊同步

9. 盡量降低對變量的反復計算

如:

for(int i = 0; i< list.size(); i++){....}

應替換為:
for(int i = 0,int len = list.size(); i < len; i++){....}
10. 盡量採用 lazy loading 的策略。在須要的時候才開始創建

如:

String str = "aaa";
if(i == 1){
	list.add(str);
}

應替換為:
if(i == 1){
	String str = "aaa";
	list.add(str);
}
11. 慎用異常,異常對性能不利

拋出異常首先要創建一個新的對象。

Throwable 接口的構造函數用名為 fillInStackTrace() 的本地方法,fillInStackTrace() 方法檢查棧。收集調用跟蹤信息。

僅僅要有異常被拋出,VM 就必要調整調用棧。由於在處理過程中創建了一個新的對象。

異常僅僅能用於錯誤處理。不應該用來控制程序流程。

12. 不要再循環中使用 Try/Catch 語句。應把其放在最外層

13. StringBuffer 的使用。 StringBuffer 表示了可變的、可寫的字符串

StringBuffer();			//默認分配16個字符的空間
StringBuffer(int size);		//分配size個字符的空間
StringBuffer(String str);	//分配16個字符+str.length()個字符空間

你能夠通過 StringBuffer 的構造函數來設定它的初始化容量,這樣能夠明顯地提升性能。

使用一個合適的容量值來初始化 StringBuffer 永遠都是一個最佳的建議。

14. 合理的使用 Java 類 java.util.Vector

簡單的說。一個Vector 就是一個 java.lang.Object 實例的數組。

Vector 與數組相似。考慮例如以下樣例:

Object obj = new Object();
Vector v = new Vector(100000);
for(int i = 0; i < 100000; i++){
	v.add(0, obj);
}

除非有絕對充足的理由要求每次都把新元素插入到 Vector 的前面,否則上面的代碼對性能不利。以下的代碼比上面的要快好幾個數量級:
Object obj = new Object();
Vector v = new Vector(100000);
for(int i = 0; i < 100000; i++){
	v.add(obj);
}
相同的規則適用於 remove() 方法。因為 Vector 中各個元素之間不能含有“空隙”。刪除除最後一個元素之外的隨意其它元素都導致被刪除元素之後的元素向前移動。也就是說。從 Vector 刪除最後一個元素要比刪除第一個元素的“開銷”低好幾倍。

for(int i = 0;  i++; i < v.length)

改成
int size = v.size()
for(int i = 0; i++;i < size)
15. 當復制大量數據時,使用 System.arraycopy() 命令

16. 代碼重構:增強代碼可讀性

17. 不用new 關鍵詞創建類的實例

將對象實現 Clonewable 接口,調用它的clone() 方法。

在設計模式的場合。用工廠模式創建對象,則改用 clone() 方法創建新的對象實例很easy。以下是工廠模式的一個典型實現:

public static Credit getNewCredit(){
	return new Credit();
}

改進後的代碼使用clone() 方法。例如以下:
private static Credit BaseCredit = new Credit();
public static Credit getNewCredit(){
	return (Credit)BaseCredit.clone();
}
上面的思路對於數組的處理相同非常實用。

18. 乘法和除法

a = a * 8; b = b * 2; 

改成移位操作:

a = a << 3; b = b << 1;

19. 不要講數組申明為:public static final

20. HaspMap 的遍歷效率

例如以下兩種方法:

Map<String, String[]> paraMap = new HashMap<String, String[]>();
//第一個循環
Set<String> appFieldDefIds = paraMap.keySet();
for(String appFieldDefId : appFieldDefIds){
	String[] values = paraMap.get(appFieldDefId);
}
//第二個循環
for(Entry<String, String[]> entry : paraMap.entrySet()){
	String appFieldDefId = entry.getKey();
	String[] values = entry.getValue();
}

第一種的實現的效率明顯不如另外一種實現。

第一種是先從 HashMap 中取得 keySet 值,另外一種則是每次循環時都取值,添加了CPU要處理的任務。

依照 Map 的概念來看,將key 和 value 分開操作在這裏不是個好選擇

21. array 和 ArrayList 的使用

array 最高效,但容量固定且無法改變

ArrayList :容量動態增長,但犧牲效率。

詳細使用視情況而定。

22. 盡量使用 HashMap 和 ArrayList

除非必要,否則不推薦使用 HashTable。和Vector。他們因為使用同步機制,導致性能的開銷。

23. StringBuffer 和 StringBuilder 的差別

java.lang.StringBuffer 線程安全的可變字符序列。一個類似於 String 的字符串緩沖區。但不能改動。

假設性能瓶頸能確定是在 StringBuffer 上。而且確定你的模塊不會執行在多線程模式下,否則還是用 StringBuffer 吧。


歡迎轉載,轉載註明出處,謝謝
Mr.傅:閱讀自《Android應用開發揭秘》


Android學習之——優化篇(1)