Android Note - 代碼優化

這篇主要講一些平時寫代碼時優化的小技巧。雖然看上去都是一些很小的細節,可是聚沙成塔,量變到必定程度也會發生質變,積累的性能提高效果仍是不可忽視的。平時碰到這些問題時必定要多留心,提高本身編碼水平的同時也能增強代碼的健壯性。算法


正確選擇數據類型

這裏簡單介紹一些經常使用的數據類型的選擇與使用場景。後端

String & StringBuilder

咱們平時在Java中作字符串鏈接的時候,下意識的選擇都是使用 + 來鏈接。這個過程其實會新生成一個 StringBuilder 對象,而後將 + 左右的數據經過 append() 方法拼接起來,本質上就是**使用StringBuilder對象進行字符串鏈接。**因此在拼接頻繁的場景(好比循環)中,若是使用 + 就至關於每次都會新建一個StringBuilder對象。而咱們知道,頻繁新建對象是很消耗性能的,並且在循環中也容易發生內存抖動。數組

結論:在單條語句中使用 + 直接拼接沒有效率問題;拼接頻繁的場景請使用 StringBuilder安全

另外,還有個StringBuffer 用法與 StringBuilder幾乎同樣,只是前者是線程安全的然後者非線程安全,這裏就不展開說了。數據結構

基本數據類型的選擇

其實原理很簡單,不一樣的數據類型,佔用的內存空間不同。好比int只佔了 4 個字節,而long佔用了 8 個字節,很明顯地處理起來 int 要快於 long。可是,在具體的工做中,由於受到各類因素的制約,好比第三方庫或者後端接口返回的數據每每不肯定,加之性能上影響其實並非很大,因此爲了保證數據正確性,對這塊的約束通常並非太嚴格。app

結論:在本身可以預見的場景中儘可能使用int short甚至byte來代替longfloat之於double同理。工具

包裝類的使用場景

雖然Java中針對每種基本數據類型,都有包裝類來對應,並且對應的包裝類都提供了自動裝箱和自動拆箱的能力,可是包裝類也不能濫用。由於在給包裝類賦值的時候,實際是經過valueOf方法去新建了一個對象,而基本數據類型的賦值倒是直接在棧空間內完成的,效率就快了不少。 可是不是包裝類就不要用了?也不是。包裝類做爲對象,提供了不少相關的操做方法,方便操做;另外一方面,包裝類能夠很方便地區分賦值與未賦值的狀況,而基本數據類型沒法區分。這是在調用後端接口時常常會碰到的狀況,因此不能一律而論。性能

結論:儘可能使用基本數據類型來賦值以提升效率;可是在區分賦值和未賦值的場景時請使用包裝類優化

變量修飾符的選擇

修飾符分爲訪問控制修飾符和非訪問控制修飾符。訪問控制修飾符就是咱們平時見到的private protected public 等對代碼訪問權限進行控制的符號,這裏就不展開講了;這裏主要談談非訪問控制修飾符,經常使用的就是static final 這兩個(volatile也先略過不提)。ui

static 靜態修飾符 使用了該修飾符,則表示該變量隨着當前類的生命週期共存亡,而且該變量會被存到方法區(JVM中的一塊固定區域)於是可被全部對象共享,即全部實例均可以經過類名來使用該變量

final 最終修飾符 使用了該修飾符,則表示此變量的生存期內,值是不可能改變的。常量若是使用final來修飾的話,讀取效率較高。

結論:很明顯,若是是常量,那麼使用 static final 來修飾是能夠提升效率的。


正確選擇數據結構

在選擇數據結構的時候,咱們有時會選擇用得最順手的那個。卻不知,不一樣的數據結構,執行效率千差萬別。正確選擇更好更高效的數據結構是代碼優化必須作到的。

ArrayList & LinkedList

這兩個數據結構都是繼承於AbstractList並實現了List接口,不一樣之處在於ArrayList底層數據結構使用的是數組,而 LinkedList底層數據結構使用的是鏈表。所以在什麼場合使用就很明顯了。

結論:**隨機查找與修改元素,使用ArrayList效率更高;對於新增和刪除元素較多的場景,則最好使用LinkedList。**這是由數組和鏈表的性質決定的

HashMap & HashSet & HashTable

這三個數據結構都是基於Hash算法的數據結構,可是底層實現都不同。HashMapHashTable 都是實現了Map 接口,可是前者繼承AbstractMap且非線程安全,後者繼承的是Dictionary是線程安全的;而HashSet實現的則是Set接口,並且效率相對於HashMap要低一些

結論:這幾個實現Hash算法的數據結構,弄清楚了他們之間的區別和聯繫,就能明白使用場景了

SparseArray & HashMap

具體來講,SparseArray 是 Android 官方推薦的一種用來代替HashMap的數據結構,更加節省內存。可是在查找效率上,SparseArray因爲查找核心算法是二分查找,比HashMap稍慢一點,可是相對來講效率損失並非很大。

結論:在須要節省內存空間,或者對增刪改查效率要求不是很是苛刻的場景,優先使用SparseArray

Serializable & Parcelabel

一樣的,Parcelabel 也是 Android 官方推薦的一種序列化/反序列化代碼的數據結構,比 Serializable 更加高效。由於在讀寫數據的時候,Parcelabel 是直接在內存中讀寫數據,而 Serializable 是經過 I/O 方式將數據讀寫在磁盤上,顯然前者讀寫速度更快

結論:優先使用 Parcelabel 序列化/反序列化,但一些場景中仍是須要使用 Serializable


善於使用位運算

在某些特定場景中,使用移位運算比直接乘除效率要高不少,這是由計算機底層特性決定的。好比 i / 2 就能夠表示爲 i >> 1

結論:培養習慣,看到這種場景要下意識想到使用位運算。但這樣會致使代碼可讀性變差,因此請清楚註釋


複用對象

由於生成一個新對象在 Java 虛擬機中是一個比較耗時耗性能的操做,並且在用完這個新對象以後,系統還要對這些生成的對象進行GC,這又是一筆性能開銷。因此,頻繁生成過多的對象對性能會形成很大影響。

結論:不要建立非必須的對象,能複用儘可能複用。尤爲是要避免在循環體內新建對象,避免內存抖動


減小沒必要要的全局變量

由於臨時變量都保存在棧裏,讀取速度比堆中要快;另外,棧中的變量在方法結束時就銷燬了,不須要進行額外的GC。

結論:在不須要的地方儘可能不要使用全局變量


在類的內部直接訪問變量

請在類的內部直接訪問私有變量,而不是經過 get set 方法來訪問,能夠提升代碼運行效率。get set 方法是提供給外部調用的

根據Android官方文檔,在沒有JIT(Just In Time)編譯器時,直接訪問變量的速度是調用Getter方法的3倍;在JIT編譯時,直接訪問變量的速度是調用Getter方法的7倍


循環體中的注意事項

循環體每每是影響效率的關鍵環節,一些影響效率的因素,原理其實很簡單,因此直接說結論。

  1. 儘可能避免在循環體中新建對象以減小內存抖動
  2. 不要把 try ... catch 語句寫在循環體內部

善用Lint進行靜態代碼分析

Lint是個很是有用的工具,通常根據Lint的提示,能夠改進不少代碼中不規範的地方,提升效率。具體使用就不展開講了,網上一搜一大把


暫時先寫這麼多,之後有補充再更新

相關文章
相關標籤/搜索