Effective Java
Effective Java阅读笔记记录
1.考虑静态工厂代替构造函数:
a.静态工厂有名字,提高代码可读性;
b.每次调用时不必创建一个新的对象,易于实现singleton;
c.可以返回原返回类型的子类对象,面向接口编程;
2.使用私有构造函数强化singleton属性:
a.通过修改getInstance() 方法轻易实现线程单例和全局单例模式;
3.通过私有构造函数强化不可实例化的能力:
a.虽然名声不好,但有些程序员喜欢使用静态方法来实现面向过程编程;
b.如java.util.Arrays,java.util.Collections的实例化是没有意义的,而抽象类又容易引起歧义;
4.避免重复创建对象:
a.对于不可变对象,如 String lily = new String("Lily"); 是没有效率的;
b.考虑到对象的重用如日志记录、随机数生成等;
c.一些可变但功能相同的对象,如 Map.entryset();
5.消除过期的对象引用:
a.避免内存泄露
ArrayList的remove方法
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
6.避免使用finalizer函数:
a.GC会在销毁对象时调用这个方法,他不稳定,并非立即执行;
b.不同JVM调用finalizer函数的时机不同,会打破平台无关性导致代码可扩展性变差;
c.使用显式终止函数,自行编写,在try{}finally{}中进行调用;
7.重写equals方法是需要遵守的约定:
a.每个实例本质上都是唯一的;
b.一个类不小心提供了“逻辑相等”的测试功能,如A.name == B.name;
c.超类已经改写了equals方法,
d.一个类时是私有的或者包私有的,可以认为它的equals方法永远不会调用;
自反性、一致性、传递性、对称性、
8.重写equals时同时重写hashCode:
a.两个相同的对象,hashCode一定相同;
b.hahshCode相同的两个对象不一定相同;
9.总是要改写toString;
10.谨慎地改写clone方法:
a.注意深拷贝和浅拷贝的区别
11.考虑实现comparable接口;
12.使类和成员的可访问能力最小化:
a.注意封装和信息隐藏;
b.解耦
c.便于故障的快速定位
d.尽可能降低可访问性(函数式编程)
13.支持非可变性:
a.不提供任何会改变任何对象域的方法;
b.保证没有可被子类改写的方法;
c.所有的域都是final的;
d.所有的域都是私有的;
e.保证对于任何可变组件的互斥访问;t1:不要让客户通过传入引用初始化、t2:确保客户无法直接获取这些引用
14.复合优于继承(包外继承);
15.要么专门为继承而设计并给出文档,要么禁止继承
a.文档必须描述每一个改动带来的影响
16.接口优于抽象类;
17.接口只用于定义类型;避免常量接口;
18.优先考虑静态成员类(内部类):
a.如果一个内部类将来可能用于其他的某个环境中,他应该是顶层类;
b.内部类:静态成员类,非静态成员类,匿名类,局部类
19.用类代替结构体
20.用类层次代替联合
21.用类和代替枚举(类型安全枚举模式)
22.用类和接口代替函数指针
23.检查参数有效性(空值等)
24.需要时使用保护性拷贝,防止构造函数引用参数发生改变;
25.谨慎设计方法的原型
a.谨慎命名
b.避免长参数列表(最多不要超过三个)
c.不要过度追求提供便利的方法
d.对于参数类型,接口优于类
26.谨慎的使用重载
27.返回零长度数组而不是null
28.为所有导出的API编写文档注释:
a.为了正确的编写API文档,你必须在每一个被导出的类、接口、构造函数、方法和域声明之前增加一个文档注释;
b.每个方法的文档注释应该简明的描述他和客户之间的约定;
29.局部变量作用域最小化
a.在第一次使用它的地方声明
b.几乎每一个变量的声明都应该包含一个初始化表达式
c.使方法小而集中
30.了解和使用库(Java api)
31.为得到精确答案,尽量避免使用double,long
a.使用int替换
b.使用BigDecimal
32.如果其他类型适合,避免使用字符串
a.字符串不适合代替其他的值类型
b.字符串不适合代替枚举类型
c.字符串不适合代替聚集类型
d.字符串不适合代替能力表
33.了解字符串连接的性能
尽量避免使用连接符拼接多个字符串
34.通过接口引用对象
a.程序更加灵活
b.适度,不要强求
35.接口优于反射
36.谨慎地使用本地方法
本地方法不可移植、性能提升已不再有明显优势
37.谨慎地进行优化
38.遵守普遍接受的命名惯例
39.只针对不正常的条件才使用异常
a.异常只用于检测不正常条件,而不能用于正常控制流
b.一个设计良好的api不应该强迫他的客户为了正常的控制流而使用异常
40.对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常
a.throwable->error、checked exception、run-time exception
b.你所实现的所有未被检查的抛出结构都应该是RuntimeException的子类(直接或间接)
41.避免不必要地使用被检查异常
使用被检查异常的两个条件:
a.正确使用api不能避免这种错误的发生
b.一旦发生异常,程序员可以采取有用的动作
42.尽量使用标准的异常
常用异常
a.illegalStateException 一个对象在完成初始化之前被调用
b.illegalArguementException 传入参数不合适
c.NullPointerException 空指针
d.IndexOutOfBandException 数组越界
e.CurrentModificationException 针对单线程的对象被其他线程修改
f.UnSupprotOperationException 对象不支持客户请求的方法
43.抛出的异常要适用于相应的抽象
44.每个方法抛出的异常都应该有文档
45.在细节消息中包含失败-捕获信息
46.努力使失败保持原子性
a.使用不可变对象
b.在调用方法前检查参数正确性
c.调整计算处理顺序,将可能发生失败的部分放在状态改变之前
d.编写恢复代码
e.临时拷贝
47.不要忽略异常
正确的处理异常能够避免不可挽回的失败
48.对共享可变数据的访问
49.避免过多的同步
a.在同步区域内做尽可能少的工作
50.永远不要在循环外面调用wait
51.不要依赖线程调度器
a.不要企图通过Thread.yield来“修正”程序
b.线程优先级是Java平台最不可移植的特征
52.线程安全性文档化
53.避免使用线程组
54.谨慎的实现序列化
a.一旦一个类的实现已经发布,则“改变这个类的实现”的灵活性将大大下降
b.增加漏洞和错误发生的可能性
c.相关测试压力增大
d.为了继承而设计的类应该很少实现Serializable,接口也很少去扩展它
e.对于为继承而设计的不可序列化类,应该为其设计一个无参构造方法
55.考虑自定义的序列化实现
a.若没有认真考虑过默认序列化形式是否合适,则不要使用这种序列化方法
b.一个对象的物理表示等同于逻辑表示,则默认的序列化形式是合适的
c.即使默认序列化形式是合适的,你也应该提供一个readObject方法保证约束关系和安全性
56.保护性的编写readObject
57.必要时提供readSolve方法