Effective Java

2018-07-11  本文已影响13人  丿九尾狸猫

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方法

上一篇下一篇

猜你喜欢

热点阅读