规则1、用静态方法代替类构造函数。
以前也用过,不过主要是在写单例模式的时候用过,看完以为使用的场景还比较多,好比一、类的实例化方法能够有具体的名字,方便使用;二、也能够返回类的子类对象。缺点以前还未想过,看完貌似有一点比较注意,类若是没有共有的或者受保护的构造函数,则该类将没法被继承。
规则2、使用私有构造函数强化singleton属性
以前一直是这样用的,具体的singleton模式,讲的不少,不在此处详解了。可是里面有讲到所谓的序列化和反序列化的东西,貌似通常的singleton模式里面不多说起,由于不多有序列化的singleton模式例子,在此点一下。
规则3、经过私有化构造函数强化不可实例化的能力
常见的应用场景,如工具类,貌似以前不多对构造函数下手,仔细想一想,仍是须要进行私有化构造函数。
规则4、避免建立重复的对象
若是一个函数被频繁的调用,则能够考虑将此函数中的变量放到函数以外,这样能够减小建立对象带来的性能损失。固然,也不要以为建立对象代价很昂贵,就如今的JVM来看,通常不须要特地去维护对象池,除非是有必要,好比数据库链接池,仍是颇有必要的,具体还有哪些,还须要继续摸索,能够进行性能上的测试和比对。
规则5、消除过时的对象引用
GC主要是回收没有被引用的对象,若是存在对象被引用,则GC是不会去回收的,除非显示的通知GC,通常来讲若是类本身管理它的内存,则须要警戒内存泄漏的问题。
规则6、避免使用终结函数
日常本身写的代码中,基本从未用到终结函数,不过看了这个规则以后,发现,有些地方仍是须要的,好比做为安全网(还未明白啥意思),或者终止非关键的本地资源。一旦使用,则将考虑使用终结函数守卫者,保证终结函数被正确的执行。若是能够的化,尽可能显示调用终止函数。
java
public class Foo { private final Object finalizerGuardian = new Object(){ @Override protected void finalize() throws Throwable { //finalize outer Foo Object super.finalize(); } }; }
规则7、在改写equals的时候请遵照通用约定
第一次接触这个是使用了Hibernate,并且使用了Set.contains()函数所必需要提供的。当时的逻辑就是经过判断ID是否相等。
通用约定,对于学过数学的人来讲仍是比较简单:
一、自反性:x.equals(x)=true
二、对称性:x.equals(y)=true => y.equals(x)=true
三、传递性:x.equals(y)=true && y.equals(z)=true => x.equals(z)=true
四、一致性:x.equals(y) is always true or false
五、非空性:x.equals(null) = false,equals方法中最好先进行instanceof检查
规则8、改下equals方法的时老是要改写hashCode方法
没什么好说的,若是用到了hashMap等之类的,必需要重写,比较好的重写方法就是作移位操做?
规则9、老是要改写toString方法
toString的通用约定指出,被返回的字符串应该是一个简洁的,但信息丰富,且易于阅读的表达形式。好比能够将toString变成json格式的输出。
规则10、谨慎的修改clone
貌似还从未接触过这个函数。貌似提供一个比本身复制对象及其内容更快的实现。
规则11、考虑实现Comparable接口
若是实现此接口,那么使用Array.sort将很是简单
规则12、使类和成员的可访问能力最小化
使得程序间耦合度下降,模块化程序,使得能够并行开发,提升开发效率,这个属于设计原则的问题。
规则十3、支持非可变性
即实例不能够修改。如String、BigInteger等,和一般的POJO类来比较 就是提供所有成员变量的一个构造函数,而后私有化全部的成员变量和成员函数。程序员
规则十4、复合优先于继承
当子类继承超类时,超类的API会显示给子类,若是超类API发生变化,子类又刚好使用了超类的API,若是超类的API发生变化,则子类也将进行修改,形成子类很是脆弱。比较好的作法是,进行复合,也就是所谓的装饰模式,这样就能够隐藏超类API的缺陷,拥抱变化。只有子类真的是超类的“子类型”的时候,继承才是合适的。
规则十5、要么专为继承而设计,并给出文档说明,要么禁止继承
该类的文档必须精确的描述改写每个方法所带来的影响。好的API文档应该描述一个方法作了什么工做,而并不是描述它是如何作到的。一个例子:超类的构造函数调用了超类中的一个API,若是子类重写了这个API,将致使程序失败。禁止子类化的方案,一、类声明为final,二、把全部的构造函数变成私有或者包级私有。
规则十6、接口优先于抽象类
由于java中只容许单继承,能够实现多个接口,因此接口使得安全地加强一个类的功能称为可能。通常来讲,能够将接口和抽象类进行组合,对于每一个指望导出的重要接口,都提供一个抽象的骨架实现。
规则十7、接口只是被用于定义类型
不用定义常量接口,比较好的方法就是定义常量工具类,私有化构造函数。
规则十8、优先考虑静态成员类
嵌套类是指被定义在另外一个类的内部类,若是这个嵌套类未来可能用于其余的某个环境,那么就应该是顶层类。嵌套类有四种:静态成员类、非静态成员类、匿名类和局部类。除了第一种,其余都被称为内部类。静态成员类就是加了static关键字,若是声明的成员类不要求访问外围实例,那么请使用静态成员类。匿名类用过不少了,不少回调函数里面就应用了匿名类做为最后一个参数,须要注意的一点就是,若是匿名类篇幅很长,设计的时候就考虑独立出来,常见用法如过程对象(Thread等)、静态工厂方法内部、复杂的类型安全枚举类型、一般只实现接口或者超类中的方法。局部类是最少使用的类,在任何能够声明局部变量的地方,均可以声明局部类。总结:若是嵌套类在单个方法以外仍然可见,或者太长,不适合放在一个方法内部,那么就应该使用成员类;若是成员类的每一个实例都须要一个指向其外围实例的引用,则把成员类作成非静态的,不然就作成静态的。假设一个成员类属于一个方法的内部,若是你只须要在一个地方建立它的实例,而且已经有了一个预先存在的类型能够说明这个类型能够说明这个类的特征,则把它作成匿名类;不然就作成局部类。
规则十9、用类代替结构
规则二10、用类层次来代替联合
类层次提供了类型安全、代码简洁明了、容易扩展、反映出类型的本质。
规则二11、用类代替enum结构
定义一个类来表明枚举类型的单个元素,而且不提供任何公有的构造函数。相反,提供共有的静态final域,使枚举类型中的每个常量都对应一个域。
规则二12、用类和接口代替函数指针
函数指针更像是策略模式的实现。
规则二十3、检查参数的有效性
没什么好说的,只是不要过分检查有效性。
规则二十4、须要时使用保护性拷贝
为了保护对象实例的内部信息避免受到攻击,对于构造函数的每一个可变参数进行保护性拷贝是必要的。注意:保护性拷贝动做是在检查参数的有效性以前进行的,而且有效性检查是针对拷贝以后的对象,而不是原始的对象。若是类提供了内部域的访问,那么要使得它返回可变内部域的保护性拷贝。
规则二十5、谨慎设计方法的原型
谨慎选择方法的名字;不要过于追求提供便利的方法;避免长长的参数列表(考虑将一个方法分解成多个方法;建立辅助类);对于参数类型,优先使用接口而不是类;谨慎的使用函数对象(常见的就是使用匿名类)。
规则二十6、谨慎的使用重载
重载的方法选择是在编译时的参数类型进行,即编译的时候参数类型决定调用的重载方法,而改写的方法选择是在执行时的参数类型,因此谨慎使用重载。一个安全而保守的策略是,永远不要导出两个具备相同参数数目的重载方法。
规则二十7、返回零长度的数组而不是null
规则二十8、为全部导出的API元素编写文档注释
注释该写清楚作了什么,而不是写如何作。同时应该列举全部的前提条件和后置条件,描述其反作用(如开启了一个后台线程)、和该类的线程安全性。
规则二十9、将局部变量的做用域最小化
尽可能在其第一次使用它的地方声明,否则等到使用该变量的时候,可能已经不记得前面该变量声明时的类型和初始值了,也不肯定其当前值。同时能够变量剪切复制带来的粗心的错误。
规则三10、了解和使用库
每一个程序员应该熟悉java.lang java.util java.io中的内容,其余库能够根据须要的时候再学习。
规则三11、若是要求精确的答案,避免使用float和double。
货币计算请使用BigDecimal、int或者long类型。
规则三12、若是其余类型更适合,请避免使用字符串。
我的也很排斥这种作法,由于若是使用字符串,则只能使用字符串提供的一些方法和工具,有时候会显的很笨拙,可是偶尔也会使用字符串,在一些特殊的地方。
规则三十3、了解字符串链接的性能
为链接n个字符串而重复的使用字符串链接操做符,要求n的平方级的时间,由于字符串是非可变的,当两个字符串被链接的时候,他们的内容都要拷贝!为了得到可接受的性能,使用StringBuilder代替String。
规则三十4、经过接口引用对象
能够保持程序的灵活性,有时候,只须要修改一行代码,就能够改变整个程序。若是须要额外的实例的方法,则须要经过类应用对象。
规则三十5、接口优先于反射
性能、可读性等方面会有损失,可是对于一些特殊的用途来讲,使用反射仍是必须的。
规则三十6、谨慎的使用本地方法
本地方法的用途:一、提供访问与平台相关的设施的能力,二、提供访问老式代码库的能力,三、经过本地语言实现性能关键的部分。可是随着1.3发行版本的推出,使用本地方法来提升性能的作法已经不提倡了。并且使用本地方法不安全。
规则三十7、谨慎的进行优化
努力写好的程序而不是快的程序。应该在设计的时候考虑好的结构,性能的优化能够在完成程序以后,固然也不是说编写程序的时候忽略性能问题。
规则三十8、遵照广泛接受的命名习惯
不严格的讲,命名惯例分为两大类:字面的和语法的。
规则三十9、只针对不正常的条件才使用异常
不要依赖异常去帮你提升性能等。
规则四10、对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常
没什么好说的,编写的时候为了可用性,须要对异常进行合理的使用。
规则四11、避免没必要要的使用被检查的异常
规则四12、尽可能使用标准的异常
了解java提供的常见异常以及相关的含义。
规则四十3、抛出的异常要适合于相应的抽象
若是一个方法抛出的异常与它执行的任务没有明显的关联关系,这种情形会令人不知所措。高层的实现应该捕获低层的异常,同时抛出一个能够按照高层抽象进行解释的异常。
规则四十4、每一个方法抛出的异常都要有文档
没什么好说的。
规则四十5、在细节消息中包含失败=捕获消息
为了捕获失败,一个异常的字符串表示应该包含全部“对异常有贡献”的参数和域的值。
规则四十6、努力使失败保持原子性
就是说一个失败的方法调用应该使对象保持“它被调用以前的状态”,具备这种属性的方法被称为具备失败原子性。这样就能够从异常中恢复过来。一般的途径是:一、设计一个非可变对象;二、在执行操做前检查参数的有效性;三、对计算过程调整顺序,使得任何可能会失败的计算部分都发生在对象状态被修改以前;四、编写一段恢复代码;五、在对象的一份临时拷贝上执行操做,当操做完成后再把临时拷贝中的结果复制个原来的对象。错误(相对异常)一般是不可恢复的。
规则四十7、不要忽略异常
空的catch块会是异常达不到应有的目的,至少也应该包含一条说明,用来解释为何忽略掉这个异常是合适的。
规则四十8、对共享可变数据的同步访问
synchronized关键字。volatile修饰符能够保证任何一个线程在读取一个域的时候都将会看到最近刚刚被写入的值。
规则四十9、避免过多的同步
过多的同步可能会致使性能下降、死锁,甚至不肯定的行为。须要对客户代码进行限制,若是客户代码也开启了线程,那么可能会出现死锁的现象。一般,在同步区域内应该作尽量少的工做。
规则五10、永远不要在循环的外面调用wait
老是使用wait循环模式来调用wait方法。循环通常用于在等待的先后测试条件。
规则五11、不要依赖于线程调度器
线程调度器会依赖具体的JVM实现,因此不要依赖于线程调度器。
规则五12、线程安全性的文档化
一个类为了可被多个线程安全使用,必须在文档中清楚的说明它所支持的现场安全性级别。
规则五十3、避免使用线程组
除了线程、锁和监视器之外,线程系统还提供了一个基本的抽象,即线程组,可是它并未提供所说起的任何安全功能!
规则五十4、谨慎的实现Serializable
一旦一个类被发布,则"改变这个类的实现"的灵活性将大大下降。并且增长了错误(bug)和安全漏洞的可能性,范序列化是机制是一种语言以外的对象建立机制。随着一个类的新版本的发行,相关的测试负担增长了。
规则五十5、考虑使用自定义的序列化形式
若没有认真考虑默认序列化形式是否合适,则不要接受这种形式。除非自行设计的自定义序列化形式与默认的基本相同。transient修饰符代表这个实例域将从一个类的默认序列化形式中省略掉。
规则五十6、保护性的编写readObject方法
在调用defaultxx函数以后,须要进行域进行校验。
规则五十7、必要时提供一个readResolve方法
若是一个单例模式实现了序列化接口,那么它就再也不是单例。除非编写正确的readResolve方法。对于一个正在范序列化的对象,若是它的类定义了readResolve方法,而且是正确的,那么反序列化以后,新建立对象上的readResolve方法就会被调用。同时readResolve方法能够做为保护性的readObject方法的一种保守的替代选择。数据库
至此,该本书已经阅读完毕,可是不少东西依然有待实践去领悟,所谓温故而知新也。关于序列化的地方,貌似还历来未考虑过,确实应该去体会体会。
json