《Android編程實(shí)戰(zhàn)》學(xué)習(xí)筆記二——在Android上編寫(xiě)高效的Java(1)

一、安卓上的類(lèi)型安全枚舉

public class Machine {
    public static final int STOPPED = 10;
    public static final int INITIALIZING = 20;
    public static final int STARTING = 30;
    public static final int RUNNING = 40;
    public static final int STOPPING = 50;
    public static final int CRASHED = 60;
    private int mState;
    public Machine() {
        mState = STOPPED;
    }
    public int getState() {
        return mState;
    }
    public void setState(int state) {
        mState = state;
    }
}

問(wèn)題:雖然這些常量是期望的,但是沒(méi)有方法保證setState()方法接收其他的值。如果
要在設(shè)置方法中添加檢查,那么一旦得到的是非預(yù)期值,開(kāi)發(fā)者就需要處理錯(cuò)誤。開(kāi)發(fā)者所需要的是在編譯時(shí)檢查非法賦值。類(lèi)型安全的枚舉解決了這個(gè)問(wèn)題,如下所示:

public class Machine {
    public enum State {
        STOPPED, INITIALIZING, STARTING, RUNNING, STOPPING, CRASHED
    }
    private State mState;
    public Machine() {
        mState = State.STOPPED;
    }
    public State getState() {
        return mState;
    }
    public void setState(State state) {
        mState = state;
    }
}

注意在聲明不同類(lèi)型安全值的地方新加的內(nèi)部枚舉類(lèi)。這在編譯時(shí)就會(huì)解決非法賦值的問(wèn)題,所以代碼更不容易出錯(cuò)。
Android早期的版本中不建議使用枚舉類(lèi)型,因?yàn)楹褪褂谜统A肯啾?,這種設(shè)計(jì)帶來(lái)的內(nèi)存和性能損失更大。如今有了更強(qiáng)的JIT編譯器以及一個(gè)不斷改進(jìn)的Dalvik虛擬機(jī),開(kāi)發(fā)者不必再擔(dān)心這個(gè)問(wèn)題,放心大膽地使用類(lèi)型安全枚舉即可。

二、增強(qiáng)for循環(huán)

void loopOne(String[] names){
    int size = names.length;
    for(int i=0;i<size;i++){
         printName(names[i]); 
    }
}

void loopTwo(String[] names){
    for(String name:names){
        printName(name);
    }
}

void loopThree(Collection<String> names){
    for(String name:names){
        printName(name);
    }  
}

void loopFour(Collection<String> names){
    Iterator<String> iterator = names.iterator();
    while(iterator.hasNext()){
        printName(iterator.next());
    }
}

// 不要在ArrayList上使用增強(qiáng)版的for循環(huán)
void loopFive(ArrayList<String> names){
    int size = names.size();
    for(int i=0;i<size;i++){
        printName(names[i]);
    }
}

如果只是讀取元素的話(huà),可以放心地對(duì)數(shù)組使用增強(qiáng)版 for 循環(huán)。對(duì) Collection 對(duì)象來(lái)說(shuō),增強(qiáng)版 for 循環(huán)和使用迭代器遍歷元素有著相同的性能。 ArrayList 對(duì)象應(yīng)避免使用增強(qiáng)版 for 循環(huán)。
如果不僅需要遍歷元素,而且需要元素的位置,就一定要使用數(shù)組或者 ArrayList ,因?yàn)樗衅渌?Collection 類(lèi)在這些情況下會(huì)更慢。
一般情況下,如果在讀取元素幾乎不變的數(shù)據(jù)集時(shí)對(duì)性能要求很高,建議使用常規(guī)數(shù)組。

三、隊(duì)列、同步和鎖

1. 更智能的隊(duì)列

LinkedBlockingQueue<String> blockingQueue = new LinkedBlockingQueue<String>();

上面的一行代碼能提供阻塞隊(duì)列,甚至能提供額外的線(xiàn)程安全操作。java.util.concurrent包含許多可選的隊(duì)列以及并發(fā)映射類(lèi),所以,一般情況下,建議使用它們。

2.更智能的鎖

Java提供的 synchronized 關(guān)鍵字允許開(kāi)發(fā)者創(chuàng)建線(xiàn)程安全的方法和代碼塊。synchronized關(guān)鍵字易于使用,也很容易濫用,對(duì)性能造成負(fù)面影響。當(dāng)需要區(qū)分讀數(shù)據(jù)和寫(xiě)數(shù)據(jù)時(shí),synchronized 關(guān)鍵字并不是最有效的。幸好,java.util.concurrent.locks包中的工具類(lèi)對(duì)這種情況提供了很好的支持。

public class ReadWriteLockDemo(){
    private final ReentrantReadWriteLock mLock;
    private String mName;
    private int mAge;
    private String mAddress;

    public ReadWriteLockDemo(){
        mLock = new ReentrantReadWriteLock();
    }

    public void setPersonData(String name, int age, String address){
        ReentrantReadWriteLock.WriteLock writeLock = mLock.writeLock();
        try{
            writeLock.lock();
            mName = name;
            mAge = age;
            mAddress = address;
        }finally{
            writeLock.unlock();
        }
    }

    public String getName() {
        ReentrantReadWriteLock.ReadLock readLock = mLock.readLock();
        try {
            readLock.lock();
            return mName;
        } finally {
            readLock.unlock();
        }
    }
// 重復(fù)代碼不再贅述
}

上面的代碼展示了在什么地方使用 ReentrantReadWriteLock ,它允許多個(gè)并發(fā)線(xiàn)程對(duì)數(shù)據(jù)進(jìn)行只讀訪(fǎng)問(wèn),并確保同一時(shí)間只有一個(gè)線(xiàn)程寫(xiě)入相同的數(shù)據(jù)。
在代碼中使用 synchronized 關(guān)鍵字仍然是處理鎖問(wèn)題的有效方法,但無(wú)論何種情況下,都要考慮 ReentrantReadWriteLock 是否是更有效的解決方案。

四、管理和分配內(nèi)存

1. 應(yīng)盡可能避免在循環(huán)中分配對(duì)象

2. 有時(shí)候無(wú)法避免在循環(huán)中創(chuàng)建對(duì)象,所以還需要采用某種方法處理這種情況。本書(shū)的解決方案是使用一個(gè)靜態(tài)工廠(chǎng)方法按需分配對(duì)象,Joshua Bloch在《Effective Java中文版》一書(shū)的第一條中詳細(xì)地描述了該方法。

public final class Pair{
    public int firstValue;
    public int secondValue;

    //引用對(duì)象池中的另一個(gè)對(duì)象
    private Pair next;

    //同步鎖
    private static final Object sPoolSync = new Object();
    //對(duì)象池中第一個(gè)可用對(duì)象
    private static Pair sPool;

    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;

    /**
    * 只能用obtain()方法獲取對(duì)象
    */
    private Pair() { }

    /**
    * 返回回收的對(duì)象或者當(dāng)對(duì)象池為空時(shí)創(chuàng)建一個(gè)新對(duì)象
    */
    public static Pair obtain(){
        synchronized(sPoolSync){
            if(sPool != null){
                Pair m = sPool;
                sPool.next = m.next;
                m.next = null;
                sPoolSize --;
                return m;
            }
        }
        return new Pair();
    }

    /**
    * 回收該對(duì)象。調(diào)用該方法后需要釋放所有對(duì)該實(shí)例的引用
    */
    public void recycle(){
        synchronized(sPoolSync){
            if(sPoolSize < MAX_POOL_SIZE){
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}

注意,本例增加了多個(gè)字段,有靜態(tài)的也有非靜態(tài)的??墒褂眠@些字段實(shí)現(xiàn)傳統(tǒng)的 Pair 對(duì)象鏈表。通過(guò)使用私有構(gòu)造函數(shù)來(lái)防止在類(lèi)外面創(chuàng)建對(duì)象,只能通過(guò) obtain 方法創(chuàng)建該類(lèi)的對(duì)象。 obtain 方法首先會(huì)檢查對(duì)象池中是否包含任何存在的對(duì)象,并刪除列表中的第一個(gè)元素然后返回它。如果對(duì)象池為空, obtain 方法會(huì)創(chuàng)建一個(gè)新的對(duì)象。要把對(duì)象重新放回池中,需要在使用完該對(duì)象時(shí),對(duì)它調(diào)用 recycle 方法。這時(shí),不能再有對(duì)該對(duì)象的引用。
另外,由于 obtain 和 recycle 是線(xiàn)程安全的,可以在多個(gè)并發(fā)線(xiàn)程中安全地使用這兩個(gè)方法。唯一的缺點(diǎn)是,必須記住要手動(dòng)調(diào)用 recycle 方法,不過(guò)這是一個(gè)很小的代價(jià)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容