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

声明

  欢迎转载,但请保留文章原始出处:) 

    博客园:http://www.cnblogs.com

    农民伯伯: http://over140.cnblogs.com

 

正文 

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

  一、性能

    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天。发现以这种方式来看书也不错,一方面能加快速度,一方面由于要写文章更加认真细读,还能提炼把书读薄记录分享出来,实在是很适合我这样的 :)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 ㆒般技術(General Techniques) 1 實踐1:引數以by value方式而非by reference方式傳遞1 實踐2:對不變的data和object reference 使用final 3 實踐3:缺省情況㆘所有non-static函數都可被覆寫6 實踐4:在arrays 和Vectors 之間慎重選擇7 實踐5:多態(polymorphism)優於instanceof 11 實踐6:必要時才使用instanceof 15 實踐7:㆒旦不再需要object references,就將它設為null 18 目錄 Practical Java viii 2 對象與相等性(Objects and Equality) 25 實踐8:區分reference type 和primitive type 25 實踐9:區分== 和 equals() 29 實踐10:不要倚賴equals()的缺省實現33 實踐11:實現equals()時必須深思熟慮 43 實踐12:實現equals()時優先考慮使用getClass() 44 實踐13:調用super.equals()以喚起base class 的相關行為47 實踐14:在equals()函數㆗謹慎使用instanceof 51 實踐15:實現equals()時需遵循某些規則 60 3 異常處理(Exception Handling) 61 實踐16:認識「異常控制流」(exception control flow)機制 62 實踐17:絕對不可輕忽異常(Never ignore an Exceptions) 65 實踐18:千萬不要遮掩異常(Never hide an Exceptions) 68 實踐19:明察throws子句的缺點 73 實踐20:細緻而全面㆞理解throws子句 74 實踐21:使用finally避免資源洩漏(resource leaks) 77 實踐22:不要從try block㆗返回 79 實踐23:將try/catch block置於循環(loop)之外 81 實踐24:不要將異常(exceptions)用於流程控制84 實踐25:不要每逢出錯就使用異常(exceptions) 85 實踐26:在構造函數(constructors)㆗拋出異常86 實踐27:拋出異常之前先將對象恢復為有效狀態(valid state) 88 目錄 Practical Java ix 4 性能(Performance) 97 實踐28:先把焦點放在設計、數據結構和算法身㆖99 實踐29:不要倚賴編譯期(compile-time)優化技術 101 實踐30:理解運行期(runtime)代碼優化技術105 實踐31:如欲進行字符串接合,StringBuffer優於String 107 實踐32:將對象的創建成本(creation cost)降至最小 109 實踐33:慎防未用㆖的對象(unused objects) 114 實踐34:將同步(synchronization)減至最低 116 實踐35:儘可能使用stack變量 122 實踐36:使用static、final和private函數以促成inlining 126 實踐37:instance變量的初始化㆒次就好 127 實踐38:使用基本型別(primitive types)使代碼更快更小 130 實踐39:不要使用Enumeration或Iterator來遍歷Vector 135 實踐40:使用System.arraycopy()來複製arrays 136 實踐41:優先使用array,然後才考慮Vector和ArrayList 138 實踐42:儘可能復用(reuse)對象 141 實踐43:使用緩式評估(延遲求值,lazy evaluation) 144 實踐44:以手工方式將代碼優化151 實踐45:編譯為本機代碼(Compile to native code) 159 5 多線程(Multithreading) 161 實踐46:面對instance函數,synchronized鎖定的是 對象(object)而非函數(method)或代碼(code) 162 目錄 Practical Java x 實踐47:弄清楚synchronized statics函數與synchronized instance函數 之間的差異 166 實踐48:以「private數據 + 相應訪問函數(accessor)」替換 「public/protected數據」 170 實踐49:避免無謂的同步控制173 實踐50:訪問共享變量時請使用synchronized或volatile 176 實踐51:在單㆒操作(single operation)㆗鎖定所有用到的對象180 實踐52:以固定而全局性的順序取得多個locks(機鎖) 以避免死鎖(deadlock) 181 實踐53:優先使用notifyAll()而非notify() 185 實踐54:針對wait()和notifyAll()使用旋鎖(spin locks) 187 實踐55:使用wait()和notifyAll()替換輪詢循環(polling loops) 191 實踐56:不要對locked object(㆖鎖對象)之object reference 重新賦值 194 實踐57:不要調用stop()或suspend() 197 實踐58:通過線程(threads)之間的協作來㆗止線程198 6 類與接口(Classes and Interfaces) 201 實踐59:運用interfaces支持多重繼承(multiple inheritance) 201 實踐60:避免interfaces㆗的函數發生衝突 206 實踐61:如需提供部分實現(partial implementation), 請使用abstract classes(抽象類) 209 實踐62:區分interface、abstract class 和concrete class 212 實踐63:審慎㆞定義和實現immutable classes(不可變類) 213 實踐64:欲傳遞或接收mutable objects(可變對象)之object references 時,請實施clone() 215 實踐65:使用繼承(inheritance)或委託(delegation)來定義 immutable classes(不可變類) 226 目錄 Practical Java xi 實踐66:實現clone()時記得調用super.clone() 233 實踐67:別只倚賴finalize()清理non-memory(內存以外)的資源 235 實踐68:在構造函數內調用non-final函數時要當心 238
中文版,平时开发超实用工具。 Java 2 Platform 软件包 java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer 提供在应用程序之间和在应用程序内部传输数据的接口和类。 java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的各类事件的接口和类。 java.awt.font 提供与字体相关的类和接口。 java.awt.geom 提供用于在与二维几何形状相关的对象上定义和执行操作的 Java 2D 类。 java.awt.im 提供输入方法框架所需的类和接口。 java.awt.im.spi 提供启用可以与 Java 运行时环境一起使用的输入方法开发的接口。 java.awt.image 提供创建和修改图像的各种类。 java.awt.image.renderable 提供用于生成与呈现无关的图像的类和接口。 java.awt.print 为通用的打印 API 提供类和接口。 java.beans 包含与开发 beans 有关的类,即基于 JavaBeansTM 架构的组件。 java.beans.beancontext 提供与 bean 上下文有关的类和接口。 java.io 通过数据流、序列化和文件系统提供系统输入和输出。 java.lang 提供利用 Java 编程语言进行程序设计的基础类。 ......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值