Effective Java读书笔记

高效Java编程规则:
一、考虑用静态工厂方法代替构造函数;
  好处:
    1、与构造函数不同,静态工厂方法具有名字;
    2、与构造函数不同,它们每次调用的时候,不要求非得创建一个新对象;
    3、与构造函数不同,它们可以返回一个原返回类型的子类型对象;
  缺点:
    1、类如果不含公有的或者受保护的构造函数,就不能被子类化;
    2、它们与其它静态方法没有任何区别;

二、使用私有的构造函数强化singleton属性;
  实现:
    1、把构造函数保持为私有的,并提供一个静态成员变量,以便客户端能访问该类唯一性的实例;
    2、把构造函数保持为私有的,提供一个公有的静态工厂方法,面不是公有的静态final域;

三、通过私有构造函数强化不可实例化的能力;

四、避免创建重复的对象;
     
五、消除过期的对象引用;

六、避免使用终结函数;
  注意:
    1、时间关键的任务不应该由终结函数来完成;
    2、我们不应该依赖一个终结函数来更新关键性的永久状态;
    3、提供一个显示的终止方法,显示终止方法通常与try-finnaly结构结合起来使用,以确保及时终止;

七、在改定equals的时候请遵守通用约定;
  不用改写的情况:
    1、一个类的每个实例本质上都是唯一的,比如Thread,Object;
    2、不关心一个类是否提供了“逻辑相等”的测试功能;
    3、超类已改写了equals,从超类继承过来的行为对子类也是合适的;
    4、一个类是私有的,或者是包级私有的,并且可以确定它的equals方法永远也不会被调用;
  改写必须遵守的通用约定:
    1、自反性:一个对象必须等于其自身;
    2、对称性:两个对象对于“它们是否相等”这个问题必须保持一致;
    3、传递性:第一个对象等于第二个对象,第二个对象等于第三个对象,则第一个对象等于第三个对象;
    4、一致性:如果两个对象相等的话,那么它们必须始终保持相等,除非有一个对象被修改了;
    5、非空性;

  实现一个高质量equals的步骤:
    1、使用“==”操作符检查“实参是否为指向对象的一个引用”;
    2、使用instanceof操作符检查“实参是否为正确的类型”;
    3、把实参转换到正确的类型;
    4、对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹配;
    5、当完成了equals方法之后,应该问自己三个问题:它是否是对称的、传递的、一致的;

  注意:
    1、当你改写equals的时候,总是要改写hashCode;
    2、不要企图让equals方法过于聪明;
    3、不要使equals方法依赖于不可靠的资源;
    4、不要将equals声明中的Object对象替换为其它的类型;

八、改写equals时总是要改写hashCode;
  hashCode约定:
    1、如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果;
    2、如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果;

九、总是要改写toString
  建议:
    1、提供一个好的toString实现,可以使一个类用起来更加愉快;
    2、在实际应用中,toString方法应该返加对象中包含的所有令人感兴趣的信息;
    3、不管你是否决定指定格式,都应该在文档中明确地表明你的意图;

十、谨慎地改写clone
  约定:
    1、如果你改写了一个非final类的clone方法,则应该返回一个通过调用super.clone而得到的对象;
    2、对于实现了cloneable的类,我们总是期望它也提供了一个功能适当的公有的clone方法;
    3、clone方法是另一个构造函数;你必须确保它不会伤害到原始的对象,并且正确地建立起被克隆对象中的约束关系;
    4、clone结构与指向可变对象的final域的正常用法是不兼容的;
    5、最好的做法是,提供某些其它的途径来代替对象拷贝,或者干脆不提供这样的能力;
    6、另一个实现对象拷贝的好方法是提供一个拷贝构造函数;

十一、考虑实现Comparable接口

十二、使类和成员的可访问能力最小化;(信息隐藏和封装)

十三、支持非可变性
  规则:
    1、不要提供任何修改对象的方法;
    2、保证没有可被子类改写的方法;
    3、使所有的域都是final的;
    4、使所有的域都成为私有的;
    5、保证对于任何可变组件的互斥访问;

  好处:
    1、非可变对象比较简单;
    2、非可变对象本质上是线程安全的,它们不要求同步;
    3、非可变对象可以被自由地共享;
    4、你不仅可以共享非可变对象,甚至也可以共享它们的内部信息;
    5、非可变对象为其他对象-无论是可变的还是非可变的-提供了大量的构件;
  缺点:
    1、对于每一个不同的值都要求一个单独的对象;

十四、复合优先于继承
  原因:
    1、与方法调用不同的是,继承打破了封装性;

十五、要么专门为继承设计,并给出文档说明,要么禁止继承
  约定:
    1、该类的文档必须精确地描述了改写每一个方法所带来的影响;
    2、一个类必须以某种形式提供适当的钩子,以便能够进入到它的内部工作流程中,这样的形式可以是精心选择的受保护的方法;
    3、构造函数一定不能调用可被改写的方法;

十六、接口优于抽象类
  原因:
    1、已有的类可以很容易被更新,以实现新的接口;
    2、接口是定义mixin的理想选择;
    3、接口可以使我们构造出非层次结构的类型框架;
    4、接口使得安全增强一个类的功能成为可能;
    5、你可以把接口和抽象类的优点结合起来,对于你期望导出的每一个重要接口,都提供一个抽象的骨架实现类;
  注意:
    1、抽象类的演化比接口的演化要容易得多;

十七、接口只是被用于定义类型
  注意:
    1、常量接口模式是对接口的不良使用;

十八、使用嵌套类优先考虑静态成员类

十九、用类代替(C语言)结构

二十、用类的层次代替联合
  好处:
    1、类层次结构提供了类型安全性;
    2、代码非常简洁明了;
    3、它很容易扩展,即使是多方独立地工作;
    4、它可以反映出这些类型之间本质上的层次关系,从而允许更强的灵活性,以及更好的编译时类型检查;

二十一、用类来代替enum结构

二十二、用类和接口来代替函数指针
  定义:
    1、函数指针:允放一个程序把“调用一个特定函数的能力”存储起来,或者传递这样的能力;(可能通过策略模式来实现)

二十三、检查参数的有效性

二十四、需要时使用保护性拷贝
  注意:
    1、假设类的客户会尽一切手段来破坏这个类的约束条件,在这样的前提下,你必须保护性的设计程序;
    2、对于构造函数的每个可变参数进行保护性拷贝是必要的;
    3、保护性拷贝动作是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是原始的对象;
    4、对于“参数类型可以被不可信方子类化”的情形,请不要使用clone方法进行参数的保护性拷贝;
    5、使它返回可变内部域的保护性拷贝

二十五、谨慎设计方法的原型
  注意:
    1、谨慎选择方法的名字;
    2、不要过于追求提供便利的方法;
    3、避免长长的参数列表;
    4、对于参数类型,优先使用接口而不是类;
    5、谨慎地使用函数对象;

二十五、谨慎地使用重载
  注意:
    1、对于重载方法的选择是静态的,而对于被改写的方法的选择是动态的;
    2、避免方法重载机制的混淆用法;
    3、一个安全而保的策略是,永远不要导出两个具有相同参数数目的重载方法;

二十七、返加零长度的数组而不是null
   描述:
      没有理由从一个取数组值的方法中返回null,而不是返回一个零长度数组;

二十八、为所有导出的API元素编写文档注释
  约定:
    1、为了正确地编写API文档,你必须在每一个被导出的类、接口、构造函数、方法和域声明之前增加一个文档注释;
    2、每一个方法的文档注释应该简洁地描述出它和客户之间的约定;

二十九、将局部变量的作用域最小化
  约定:
    1、使一个局部变量的作用域最小化,最有力的技术是在第一次使用它的地方声明;
    2、几乎每一个局部变量的声明都应该包含一个初始化表达式;
    3、如果在循环终止之后循环变量的内容不再被需要的话,则for循环优先于while循环;

三十、了解和使用库
  优点:
    1、通过标准库,你可以充分利用这些编写标准库的专家的知识,以及在你之前其他人的使用经验;

  注意:
    1、在每一个主要的发行版本中,都会有许多新的特性被加入到库中,所以与这些库保持同步是值得的;
    2、每一个程序员应该熟悉java.lang、java.util,某种程度还有java.io中的内容;

三十一、如果要求精确的答案,请避免使用float和double
  注意:
    1、float和double的类型对于货币计算尤为不合适;

三十二、如果其他类型更适合,则尽量避免使用字符串
  约定:
    1、字符串不适合代替其他的值类型;
    2、字符串不适合代替枚举类型;
    3、字符串不适合代替聚集类型;
    4、字符串也不适合代替能力表;

三十三、了解字符串连接的性能
  注意:
    1、为连接n个字符串而重复地使用字符串连接操作符,要求n的平方级的时间;

三十四、通过接口引用对象
  注意:
    1、如果你养成了使用接口作为类型的习惯,那么你的程序将会更加灵活;
    2、如果没有合适的接口存在的话,那么,用类而不是接口来引用一个对象,是完全合适的;

三十五、接口优先于映像机制(反射机制)
  映像机制缺点:
    1、你损失了编译时类型检查的好处;
    2、要求执行映像访问的代码非常笨拙和冗长;
    3、性能损失;
  约定:
    1、通常,普通应在运行时刻不应该以映像方式访问对象;
    2、如果只是在很有限的情况下使用映像机制,那么虽然也会付出少许代价,但你可以获得许多好处;
    3、你可以经映像方式创建实例,然后通过它们的接口或者超类,以正常方式访问这些实例;

三十六、谨慎地使用本地方法

三十七、 谨慎地进行优化
  约定:
    1、努力编写好的程序而不是快的程序;
    2、努力避免那些限制性能的设计决定;
    3、考虑你的API设计决定的性能后果;
    4、为获得好的性能而对API进行曲改,这是一个非常不好的想法;
    5、在每次试图做优化之前和之后,请对性能进行测量;

三十八、遵守普遍接受的命名惯例

三十九、只针对不正常的条件才使用异常
  注意:
    1、异常只应该被用于不正常的条件,它们永远不应该被用于正常的控制流;
    2、一个设计良好的API不应该强迫它的客户为了正常的控制流而使用异常;

四十、对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常
  约定:
    1、如果期望调用者能恢复,那么,对于这样的条件应该使用被检查的异常;
    2、用运行时异常来指明程序来指明程序错误;
    3、你所实现的所有的未被检查的抛出结构都应该是RuntimeException的子类;

四十一、避免不必要地使用被检查的异常

四十二、尽量使用标准的异常

四十三、抛出的异常要适合相应的抽象
  注意:
    1、高层的实现应该捕获低层的异常,同时抛出一个可以按照高层抽象进行解释的异常;
    2、尽管异常转译比不加选择地传递低层异常的做法有所改进,但是它也不能被滥用;

四十四、每个方法抛出的异常都要有文档
  注意:
    1、总是要单独地声明被检查的异常,并且利用javadoc的@throws标记,准确地记录下每个异常被抛出的条件;
    2、使用javadoc的@throws标签记录下一个方法可能会抛出的每个未被检查的异常,但是不要使用throws关键字将未被检查的异常包含在方法的声明中;
    3、如果一个类中的许多方法出于同样的原因而抛出同一个异常,那么在该类的文档注释中对这个异常做文档,而不是为每个方法单独做文档,这是可以接受的;

四十五、在细节消息中包含失败-捕获信息
  注意:
    1、为了捕获失败,一个异常的字符串表示应该包含所有“对该异常有贡献”的参数和域的值;

四十六、努力使失败保持原子性
  注意:
    1、一般而言,一个失败的方法调用应该使对象保持“它在被调用之前的状态”;

四十七、不要忽略异常
  注意:
    1、空的catch块会使异常达不到应有的目的;
    2、到少catch块也应该包含一条说明,用来解释为什么忽略掉这个异常是合适的;

四十八、对共享可变数据的同步访问

四十九、避免过多的同步

五十、永远不要在循环的外面调用wait

五十一、不要依赖于纯种调度器

五十二、线程安全性的文档化

五十三、避免使用线程组

五十四、谨慎地实现Serializable

五十五、考虑使用自定义的序列化形式

五十六、保护性地编写readObject方法

五十七、必要时提供一个readResolve方法

你可能感兴趣的:(java,设计模式,多线程,数据结构,读书)