effective java学习笔记

1.考虑用静态工厂方法代替构造器

  • 静态方法有名称,通过静态方法可以很明确的知道返回的是什么对象。例如BigInteger.probablePrime()
  • 静态方法不必每次都创建一个新的实例。对于某些返回对象是不可变类时可以提升性能。例如Boolean.valueOf(boolean)
  • 静态方法可以返回任何类型的子类型。这样面对接口编程的时候,我们可以不关心返回对象的具体的实现,只关心接口暴露的方法即可
  • 在创建参数化实例的时候,可以使代码变得更加简洁。比如:
1
2
3
4
5
Map<String, List<String>> m = new HashMap<String, List<String>>();
public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K ,V>();
}
Map<String, List<String>> m = HashMap.newInstance();

2.在遇到多个构造器参数时考虑用Builder

1
2
3
4
5
6
7
8
9
10
11
public class Person {
private int mAge;
private String mName;
private int mHeight;
public Person(int age, String name, int height) {
mAge = age;
mName = name;
mHeight = height;
}
}

例如一个对象有多个属性需要设置,我们可以在构造方法中设置,如下,但是在调用时会
Person person = new Person(19, “名字”, 180);如果参数一旦变多则维护起来略麻烦,这时会考虑使用set方法,但是使用set方法在多线程中是不安全的,这时可以考虑采用Builder模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Person {
private int mAge;
private String mName;
private int mSex;
private Person(Builder builder) {
mAge = builder.mAge;
mName = builder.mName;
mSex = builder.mSex;
}
public static class Builder {
private int mAge;
private String mName;
private int mSex;
public Builder name(String name) {
mName = name;
return this;
}
public Builder age(int age) {
mAge = age;
return this;
}
public Builder sex(int sex) {
mSex = sex;
return this;
}
public Person build() {
return new Person(this);
}
}
}
//调用时
Person person = new Person.Builder()
.age(19)
.name("名字")
.sex(1)
.build();

通过上面这种方式很清晰。

3.用私有构造器或者枚举属性强化Singleton属性

在java1.5后可以通过枚举来实现单例,这种方法简洁,而且创建的过程是线程安全的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum Person {
INSTANCE;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
Person.INSTANCE.setName("kevin");
System.out.println(Person.INSTANCE.getName());

4.通过私有构造器强化不可实例化的能力

对于一些工具类来说,它只存在静态方法,这时它并不想被实例化,因此最好强化不可实例化的能力,给它添加私有构造器。

5.避免创建不必要的对象

String s = new String("kevin");

在这里”kevin” 本来就是一个String对象,这时就多创建了一个对象。
同时除了重用不可变对象之外,也可以重用已知不会被修改的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public enum Person {
private final Date birthDate;
public boolean isBabyBoomer() {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965 ,Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0
&& birthDate.compareTo(boomEnd) < 0;
}
}
//在这里start和end都是不变的,而每次比较时都会生成2个Date同样的对象。
public enum Person {
private final Date birthDate;
private static Date boomStart;
private static Date boomEnd;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
boomStart = gmtCal.getTime();
gmtCal.set(1965 ,Calendar.JANUARY, 1, 0, 0, 0);
boomEnd = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(boomStart) >= 0
&& birthDate.compareTo(boomEnd) < 0;
}
}

因为Java的自动装箱机制导致下面的代码会产生很多对象

1
2
3
4
Long l = 0L;
for(long i = 0;i < Long.MAX_VALUE; i++) {
l += i;
}

6.消除过期的引用

Java