《Android编程实战》学习笔记二——在Android上编写高效的Java(1)

一、安卓上的类型安全枚举

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;
    }
}

问题:虽然这些常量是期望的,但是没有方法保证setState()方法接收其他的值。如果
要在设置方法中添加检查,那么一旦得到的是非预期值,开发者就需要处理错误。开发者所需要的是在编译时检查非法赋值。类型安全的枚举解决了这个问题,如下所示:

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;
    }
}

注意在声明不同类型安全值的地方新加的内部枚举类。这在编译时就会解决非法赋值的问题,所以代码更不容易出错。
Android早期的版本中不建议使用枚举类型,因为和使用整型常量相比,这种设计带来的内存和性能损失更大。如今有了更强的JIT编译器以及一个不断改进的Dalvik虚拟机,开发者不必再担心这个问题,放心大胆地使用类型安全枚举即可。

二、增强for循环

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上使用增强版的for循环
void loopFive(ArrayList<String> names){
    int size = names.size();
    for(int i=0;i<size;i++){
        printName(names[i]);
    }
}

如果只是读取元素的话,可以放心地对数组使用增强版 for 循环。对 Collection 对象来说,增强版 for 循环和使用迭代器遍历元素有着相同的性能。 ArrayList 对象应避免使用增强版 for 循环。
如果不仅需要遍历元素,而且需要元素的位置,就一定要使用数组或者 ArrayList ,因为所有其他 Collection 类在这些情况下会更慢。
一般情况下,如果在读取元素几乎不变的数据集时对性能要求很高,建议使用常规数组。

三、队列、同步和锁

1. 更智能的队列

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

上面的一行代码能提供阻塞队列,甚至能提供额外的线程安全操作。java.util.concurrent包含许多可选的队列以及并发映射类,所以,一般情况下,建议使用它们。

2.更智能的锁

Java提供的 synchronized 关键字允许开发者创建线程安全的方法和代码块。synchronized关键字易于使用,也很容易滥用,对性能造成负面影响。当需要区分读数据和写数据时,synchronized 关键字并不是最有效的。幸好,java.util.concurrent.locks包中的工具类对这种情况提供了很好的支持。

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();
        }
    }
// 重复代码不再赘述
}

上面的代码展示了在什么地方使用 ReentrantReadWriteLock ,它允许多个并发线程对数据进行只读访问,并确保同一时间只有一个线程写入相同的数据。
在代码中使用 synchronized 关键字仍然是处理锁问题的有效方法,但无论何种情况下,都要考虑 ReentrantReadWriteLock 是否是更有效的解决方案。

四、管理和分配内存

1. 应尽可能避免在循环中分配对象

2. 有时候无法避免在循环中创建对象,所以还需要采用某种方法处理这种情况。本书的解决方案是使用一个静态工厂方法按需分配对象,Joshua Bloch在《Effective Java中文版》一书的第一条中详细地描述了该方法。

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

    //引用对象池中的另一个对象
    private Pair next;

    //同步锁
    private static final Object sPoolSync = new Object();
    //对象池中第一个可用对象
    private static Pair sPool;

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

    /**
    * 只能用obtain()方法获取对象
    */
    private Pair() { }

    /**
    * 返回回收的对象或者当对象池为空时创建一个新对象
    */
    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();
    }

    /**
    * 回收该对象。调用该方法后需要释放所有对该实例的引用
    */
    public void recycle(){
        synchronized(sPoolSync){
            if(sPoolSize < MAX_POOL_SIZE){
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}

注意,本例增加了多个字段,有静态的也有非静态的。可使用这些字段实现传统的 Pair 对象链表。通过使用私有构造函数来防止在类外面创建对象,只能通过 obtain 方法创建该类的对象。 obtain 方法首先会检查对象池中是否包含任何存在的对象,并删除列表中的第一个元素然后返回它。如果对象池为空, obtain 方法会创建一个新的对象。要把对象重新放回池中,需要在使用完该对象时,对它调用 recycle 方法。这时,不能再有对该对象的引用。
另外,由于 obtain 和 recycle 是线程安全的,可以在多个并发线程中安全地使用这两个方法。唯一的缺点是,必须记住要手动调用 recycle 方法,不过这是一个很小的代价。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容