Android应用开发提高系列(2)——《Practical Java 中文版》读书笔记(下)

简介:

正文 

注意:条目和用语可能与书籍有所出入,但尽量保持原样加一些自己的理解。

  一、性能

    1. 先把焦点放在设计、数据结构和算法身上

      备注:良好的设计、明智的选择数据结构和算法可能比高效代码更重要。

 

    2.  不要依赖编译器优化技术

 

    3.  理解运行时(runtime)代码优化

      备注:JIT将bytecode于运行时转换为本地二进制码,从而提高性能。因此编译后代码被执行次数越多,本机代码生成代价就很合算。

 

    4.  连接字符串使用StringBuffer要比String快,尤其是大量字符串拼接

 

    5.  将对象创建成本降至最小

      备注:复用既有对象,不要创建非必要的对象,只在需要的时候才创建它们。

 

    6.  将同步化(synchronization)降至最低

      备注:如果synchronized函数抛出异常,则在异常离开函数之前,锁会自动释放。如果整个函数都需要被同步化,为了产生体积较小且执行速度较快的代码,请优先使用函数修饰符,而不是在函数内使用synchronized代码块。

 

    7.  尽可能使用stack变量

      备注:如果在函数中频繁访问成员变量、静态变量,可以用本地(local)变量替代,最后操作完后再赋值给成员/静态变量。

 

    8.  尽可能的使用static、final和private函数

      备注:此类函数可以在编译期间被静态决议(statically resolved),而不需要动态议决(dynamic resolved)。(子类无法覆写)

 

    9.  类的成员变量、静态变量都有缺省值,务须重复初始化

      备注:记住,本地变量没有缺省值(例如函数内定义的变量)。

 

    10.  尽可能的使用基本数据类型

      备注:如int、short、char、boolean,使得代码更快更小。

 

    11.  不要使用枚举器(Enumeration)和迭代器(Iterator)来遍历Vector

      备注:使用for循环+get()

 

    12.  使用System.arraycopy()来复制数组

      备注:使用System.arraycopy()代替for循环,可以产生更快的代码。如:

         public  void copyArray( int[] src,  int[] dest) {
             int size = src.length;
            System.arraycopy(src, 0, dest, 0, size);
        }

 

      System.arraycopy()是以native method实现的,可以直接、高效的移动原始数组到目标数组,因此它执行速度更快。

 

    13.  优先使用数组,然后才考虑Vector和ArrayList,理由:

      a).  Vector的get()是同步的

      b).  ArrayList基本上就是一个非线程同步的Vector,比Vector要快

      c).  ArrayList和Vector添加元素或移除元素都需要重新整理数组。

      备注:不要仅仅因为手上有个数不定的数据需要存储,就毫无选择的使用Vector或ArrayList。可以考虑创建一个足够大的数组,通常这样可能会浪费内存,但性能上的收益可能超过内存方面的代价。

 

    14.  手工优化代码

      a).  剔除空白函数和无用代码

      b).  削减强度

        备注:以更高效的操作替换成本昂贵的操作。一个常见的优化手法是使用复式复制操作符(如+=、-=)。

      c).  合并常量

        备注:将变量声明为final,使得操作在编译器就进行。

      d).  删减相同的子表达式

        备注:可用一个临时变量代替重复的表达式。

      e).  展开循环

        备注:如循环次数少且已知循环次数,可展开去掉循环结构,直接访问数组元素。缺点是会产生更多代码。

      f).  简化代数

        备注:使用数学技巧来简化表达式。(例如从1+..+100的问题)

      g).  搬移循环内的不变式

        备注:循环内不变化的表达式可用移至循环外,不必重复计算表达式。

 

    15.  编译为本机代码

      备注:将程序的某部分编译为本机二进制代码,然后通过JNI访问。

 

  二、多线程

    1.  对于实例(instance)函数,同步机制锁定的是对象,而不是函数和代码块。

      备注:函数或代码块被声明为synchronized并非意味它在同一时刻只能有一个线程执行(同一对象不同线程调用会阻塞)。Java语言不允许将构造函数声明为synchronized。

 

    2.  同步实例函数和同步静态函数争取的是不同的locks。

      备注:两者均非多线程安全,可以使用实例变量进行同步控制,如(byte[] lock = new byte[0]),比其他任何对象都经济。

 

    3.  对于synchronized函数中可被修改的数据,应使之成为private,并根据需要提供访问函数。如果访问函数返回的是可变对象,那么可以先克隆该对象。

 

    4.  避免无谓的同步控制

      备注:过度的同步控制可能导致代码死锁或执行缓慢。再次提醒,当一个函数声明为synchronized,所获得的lock是隶属于调用此函数的那个对象。

 

    5.  访问共享变量时请使用synchronized或volatile

      备注:如果并发性很重要,而且不需要更新很多变量,则可以考虑使用volatile。一旦变量被声明为volatile,在每次访问它们时,它们就与主内存进行一致化。如果使用synchronized,只在取得lock和释放lock时候才一致化。

 

    6.  在单一操作(single operation)中锁定所有用到的对象

      备注:如果某个同步函数调用了某个非同步实例函数来修改对象,它是线程安全的。使用同步控制时,一定要对关键字synchronized所作所为牢记在心。它锁定的是对象而非函数或代码。

 

    7.  以固定而全局性的顺序取得多个locks(机制)以避免死锁。P/181~P/185

      备注:嵌入[锁定顺序]需要额外的一些工作、内存和执行时间。

 

    8.  优先使用notifyAll()而非notify()

      备注:notify()和notifyAll()用以唤醒处以等待状态的线程,waite()则让线程进入等待状态。notify()仅仅唤醒一个线程。

 

    9.  针对wait()和notifyAll()使用旋转锁(spin locks)

      备注:旋转锁模式(spin-lock pattern)简洁、廉价,而且能确保等待着某个条件变量的代码能循规蹈矩。

 

    10.  使用wait()和notifyAll()替代轮询(polling loops)

      备注:调用wait()时会释放同步对象锁,暂停(虚悬,suspend)此线程。被暂停的线程不会占用CPU时间,直到被唤醒。如:

             public  void run()
            {
                 int data;
                 while( true){
                     synchronized (pipe) {
                         while((data = pipe.getDate()) == 0){
                             try{
                                pipe.waite();
                            }
                             catch(InterruptedException e){}
                        }
                    }
                    
                     // Process Data
                }
            }

 

    11.  不要对已锁定对象的对象引用重新赋值。

 

    12.  不要调用stop()和suspend()

      备注:stop()中止一个线程时,会释放线程持有的所有locks,有搅乱内部数据的风险;suspend()暂时悬挂起一个线程,但不会释放持有的locks,可能带来死锁的风险。两种都会引发不可预测的行为和不正确的行为。

      当线程的run()结束时,线程就中止了运行。可以用轮询+变量来控制,如下代码:

             private  volatile  boolean stop;
            
             public  void stopThread()
            {
                stop =  true;
            }
    
             public  void run()
            {
                 while(!stop){
                     // Process Data
                }
            }

        注意:这里使用了关键字volatile,由于Java允许线程在其 私有专用内存 中保留主内存变量的副本(可以优化),线程1对线程2调用了stopThread(),但线程2可能不会及时察觉到stop主内存变量已变化,导致不能及时中止线程。

 

  三、类与接口 

    1.  实现一个final类(immutable class 不可变类)时,请遵循下列规则:

      a). 声明所有数据为private

      b).  只提供取值函数(getter),不提供赋值函数(setter)

      c).  在构造函数中设置有实例数据

      d).  如果函数返回、接受引用final对象,请克隆这个对象。

      e).  区别浅层拷贝和深层拷贝应用场景。如拷贝Vector需要使用深层拷贝。

 

    2.  实现clone()时记得调用super.clone()

      备注:不管是浅层拷贝还是深层拷贝都需要调用super.clone()。

 

    3.  别只依赖finalize()清理内存以外的资源

      备注:finalize()函数只有在垃圾回收器释放对象占用的空间之前才会被调用,回收时可能并非所有符合回收条件的对象都被回收,也无法保证是否被调用、何时调用。实现finalize()方法时记得调用super.finalize()。

 

    4.  在构造函数内应避免调用非final函数,以免被覆写而改变初衷。

 

结束

  书是从朋友那边借过来的,拿到手也有一段时间,磨磨唧唧好多天才看了几十页,而余下部分从上篇文章到这篇文章也不过才3-5天。发现以这种方式来看书也不错,一方面能加快速度,一方面由于要写文章更加认真细读,还能提炼把书读薄记录分享出来,实在是很适合我这样的 :)


本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/844924,如需转载请自行联系原作者

相关文章
|
7天前
|
IDE Java 程序员
安卓应用开发入门:打造你的第一个“Hello World”
【9月更文挑战第11天】在编程的世界里,每一个初学者的旅程都从一个简单的“Hello World”开始。本文将带领安卓开发的新手们,通过简单直观的方式,一步步构建出自己的第一个安卓应用。我们将探索安卓工作室(Android Studio)的安装、项目的创建,以及如何运行和调试你的应用。无论你是编程新手还是想扩展技能的老手,这篇文章都将为你打开一扇通往安卓世界的大门。
38 7
|
5天前
|
前端开发 Android开发 开发者
安卓应用开发中的自定义视图基础
【9月更文挑战第13天】在安卓开发的广阔天地中,自定义视图是一块神奇的画布,它允许开发者将想象力转化为用户界面的创新元素。本文将带你一探究竟,了解如何从零开始构建自定义视图,包括绘图基础、触摸事件处理,以及性能优化的实用技巧。无论你是想提升应用的视觉吸引力,还是追求更流畅的交互体验,这里都有你需要的金钥匙。
|
5天前
|
API Android开发 iOS开发
掌握安卓与iOS应用开发中的依赖注入技术
本文探讨了在安卓和iOS应用开发中,如何有效利用依赖注入技术来提升代码的模块化、可测试性和可维护性。通过对比分析两种平台下依赖注入的实现方式与工具,本文旨在为开发者提供一套清晰、实用的依赖管理策略,助力打造高质量软件产品。
|
7天前
|
IDE 开发工具 Android开发
探索iOS与安卓应用开发的异同
在数字时代的浪潮中,移动应用开发成为连接用户与企业的桥梁。本文将深入探讨iOS和安卓这两大主流平台在应用开发上的差异与共通之处,从技术架构、开发工具、市场定位到用户群体等方面进行全面分析,旨在为开发者提供清晰的指导和参考。通过比较这两个系统的开发环境,我们将揭示它们各自的优势和挑战,以及如何根据项目需求选择合适的平台。
|
7天前
|
Java Android开发 UED
安卓应用开发中的内存管理优化技巧
在安卓开发的广阔天地里,内存管理是一块让开发者既爱又恨的领域。它如同一位严苛的考官,时刻考验着开发者的智慧与耐心。然而,只要我们掌握了正确的优化技巧,就能够驯服这位考官,让我们的应用在性能和用户体验上更上一层楼。本文将带你走进内存管理的迷宫,用通俗易懂的语言解读那些看似复杂的优化策略,让你的开发之路更加顺畅。
15 2
|
7天前
|
IDE Java API
安卓应用开发入门:打造你的第一个"Hello World"
【9月更文挑战第11天】在探索安卓开发的海洋中,每个开发者的航行都从简单的"Hello World"开始。本文将作为你的航标,引导你驶向安卓应用开发的精彩世界。我们将一起启航,通过浅显易懂的语言和步骤,学习如何构建并运行你的第一个安卓应用。无论你是编程新手还是希望扩展技能的老手,这篇文章都将为你提供所需的知识和信心。准备好了吗?让我们揭开安卓开发的神秘面纱,一起创造些令人兴奋的东西吧!
|
5天前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
16 0
|
4天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
15天前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
75 6
【Java学习】多线程&JUC万字超详解
|
9天前
|
Java 调度 开发者
Java并发编程:深入理解线程池
在Java的世界中,线程池是提升应用性能、实现高效并发处理的关键工具。本文将深入浅出地介绍线程池的核心概念、工作原理以及如何在实际应用中有效利用线程池来优化资源管理和任务调度。通过本文的学习,读者能够掌握线程池的基本使用技巧,并理解其背后的设计哲学。