Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android學習之——優化篇(1)

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

編輯:關於Android編程

一、優化的品質

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. 用戶察覺性能


四、 初級優化

在 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() 方法創建新的對象實例非常簡單。下面是工廠模式的一個典型實現:

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 paraMap = new HashMap();
//第一個循環
Set appFieldDefIds = paraMap.keySet();
for(String appFieldDefId : appFieldDefIds){
	String[] values = paraMap.get(appFieldDefId);
}
//第二個循環
for(Entry 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應用開發揭秘》


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved