EffectiveJAVA.html
Effective JAVA
第2章 创建销毁对象
1.考虑用静态工厂方法代替构造器
优点
·静态工厂方法有名称
·不用每次都创建新实例
·可以返回远返回类型的任何子类型的对象
·在创建参数化类型实例的时候代码更简洁
缺点
·不能被子类化
·它们与其他的静态方法实际上没有任何区别
2.遇到多个构造器参数时要考虑用构造器
如果类的构造器或者静态工厂中具有多个参数,可以考虑使用Builder模式
3.用私有构造器或者枚举类型强化Singleton属性
编写一个包含单个元素的枚举类型
public enum Elvis{
INSTANCE;
public void leaveTheBuilding*(){
...}
}
">
public enum Elvis{
INSTANCE;
public void leaveTheBuilding*(){
...}
}
4.通过私有构造器强化不可实例化的能力
让不需要实例化的类拥有私有(private)构造器来避免被实例化
//Noninstantiable utility class
public enum UtilityClass{
private UtilityClass(){
throw new AssertinError();
}
...
}
">
public enum UtilityClass{
private UtilityClass(){
throw new AssertinError();
}
...
}
5.避免创建不必要的对象
使用静态的初始化器(initialize)避免创建重复的Calendar,TimeZone和Date实例
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Person {
private Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) <= 0;
}
}
">
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Person {
private Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone(
"GMT"));
gmtCal.set(
1946, Calendar.JANUARY,
1,
0,
0,
0);
BOOM_START = gmtCal.getTime();
gmtCal.set(
1965, Calendar.JANUARY,
1,
0,
0,
0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >=
0 && birthDate.compareTo(BOOM_END) <=
0;
}
}
优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。
6.消除过期的对象引用
一旦对象引用已经过期,只需清空这些引用即可。
7.避免使用终结方法
终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。
不应该依赖终结方法来更新重要的持久状态。
显式终止方法的典型例子:InputStream,OutputStream,java.sql.Connection的Close
第3章 对于所有对象都通用的方法
8.覆盖equals时请遵守通用约定
·类的每个实例本质上都是唯一的
·不关心类是否提供了“逻辑相等”
·超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的
·类是私有的或是包级私有的,应该覆盖父类的equals方法保证永远不会被调用
9.覆盖equals时总要覆盖hashCode
10.始终要覆盖toString
11.谨慎地覆盖clone
12.考虑实现Comparable接口
第4章 类和接口
13.使类和成员的可访问性最小化
14.在公有类中使用访问方法而非公有域
15.使可变性最小化
1.不要提供任何会修改对象状态的方法
2.保证类不会被扩展
3.使所有域都是final
4.使所有域都成为私有的
5.确保对于任何可变组建的互斥访问
16.复合优先于继承
17.要么为继承而设计,并提供文档说明,要么就禁止继承
18.接口优于抽象类
- 现有的类可以很容易被更新,以实现新的接口
- 接口是定义minin(混合类型)的理想选择
- 接口允许我们构造非层次结构的类型框架
19.接口只用于定义类型
20.类层次优于标签类
21.用函数对象表示策略
22.优先考虑静态成员类
第5章 泛型
23.请不要在新代码中使用原生态类型
24.消除非受检警告
SuppressWarnings注解始终在尽可能小的范围中使用。
25.列表预先于数组
数组是协变得(covariant)。
数组是具体化的。
26.优先考虑泛型
27.优先考虑泛型方法
28.利用有限制通配符来提升API的灵活性
29.优先考虑类型安全的已购容器
第6章 枚举和注解
30.用enum代替int常量
31.用实例域代替序数
32.用EnumSet代替位域
33.用EnumMap代替序数索引
34.用接口模拟可伸缩的枚举
35.注解优先于命名模式
36.坚持使用Override注解
37.用标记接口定义类型
第7章 方法
38.检查参数的有效性
39.必要时进行保护性拷贝
40.谨慎设计方法签名
谨慎地选择方法的名称
不要过于追求提供便利的方法
避免过长的参数列表
41.慎用重载
42.慎用可变参数
43.返回零长度的数组或集合,而不是null
44.为所有到处的API元素编写文档注释
第8章 通用程序设计
45.将局部变量的作用域最小化
46.for-each循环优先于传统的for循环
无法使用for-each的情形
1.过滤
2.转换
3.平行迭代
47.了解和使用类库
48.如果需要精确的答案,请避免使用float和double
正确的做法:使用BigDecimal,int或者long进行货币计算
49.基本类型优先于装箱基本类型
50.如果其他类型更适合,则尽量避免使用字符串
字符串不适合替代其他的值类型
字符串不适合代替枚举类型
字符串不适合替代聚集类型
字符串也不适合太呆能力表(capabilities)
51.当心字符串连接的性能
52.通过接口引用对象
53.接口优先于反射机制
反射机制的代价
丧失了编译时类型检查的好处
执行反射访问所需要的代码非常笨拙和冗长
性能损失
54.谨慎地使用本地方法
55.谨慎地进行优化
56.遵守普遍接受的命名惯例
第9章 异常
57.只针对异常的情况才使用异常
58.对可恢复的情况使用受检异常,对编程错误使用运行时异常
JAVA提供了三种可抛出结构(throwable)
1.受检的异常(checked exception)
2.运行时异常(run-time exception)
3.错误(error)
59.避免不必要地使用受检的异常
60.优先使用标准的异常
61.抛出与抽象相对应的异常
62.每个方法抛出的异常都要有文档
63.在细节信息中包含能捕获失败的信息
64.努力使失败保持原子性
65.不要忽略异常
第10章 并发
66.同步访问共享的可变数据
关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法,或者某一个代码块。
67.避免过度同步
68.executor和task优先于线程
69.并发工具优先于wait和notify
70.线程安全性的文档化
71.慎用延迟初始化
72.不要依赖于线程调度器
73.避免使用线程组
第11章 序列化
74.谨慎地实现Serializable接口
代价
1.实现Serializable接口而付出的最大代价是,可改变性变低
2.增加了出现Bug和安全漏洞的可能性
3.随着类发行新的版本,相关的测试负担也增加了
75.考虑使用自定义的序列化形式
76.保护性地编写readObject方法
77.对于实例控制,枚举类型优先于readResolve
78.考虑用序列化代理代替序列化实例