《Effective Java》阅读笔记,用适合自己理解的方式提炼该书内容。《Effective Java》是一本很实用的书,阅读方法应该是快速的领会,总结,然后应用。而非,一个字一个字去推敲,研究。所以,书呆子们一般都很xx,在我眼里。
2016.07.24作
1,用静态方法替代构造器,下面是很好的例子:
public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
结合代码来谈,valueOf比构造函数更能体现其意义;其次,valueOf返回的是final static成员,这种情况避免了创建不必要的对象。
2,构建器Builder。这个太棒了,使用了java的内部类。
package cn.j; public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbonhydrate; public static class Builder {
private final int servingSize;
private final int servings; private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbonhydrate = 0; public Builder(int servingSize,int serving){
this.servingSize = servingSize;
this.servings = serving;
} public Builder calories(int val){
this.calories = val;
return this;
} public Builder fat(int val){
this.fat = val;
return this;
} public Builder carbonhyate(int val){
this.carbonhydrate = val;
return this;
} public Builder sodium(int val){
this.sodium = val;
return this;
} public NutritionFacts build(){
return new NutritionFacts(this);
}
} private NutritionFacts(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbonhydrate = builder.carbonhydrate;
} public static void main(String[] args) {
NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build();
}
}
结合代码来看,如果单纯用构造函数来初始化那些参数的话,会比较麻烦,而难以阅读,使用易于出错。
例如new Test(1,2,3,4,5,6,7,8,9);这种写法。
上述代码的形式,NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build();可读性非常强。builder模式模拟了具名的可选参数。
我隐约记得,目前工作中的项目看到过这种Builder的写法。
3,通过私有构造器强化不可实例化的能力,这也是非常非常实用!因为项目中工具类太常用,都需要这种强化不可实例化的能力。下面代码是我自己SonnBlog的代码:
/**
* @ClassName: StringUtil
* @Description: 字符串处理工具类
* @author 无名
* @date 2016-4-30 下午10:26:48
* @version 1.0
*/
public final class StringUtill
{
private StringUtill()
{
} public static boolean isStringEmpty(String str)
{
if(null == str|| "".equals(str))
{
return true;
}
return false;
} public static boolean isTheSameStr(String str1,String str2)
{
if(isStringEmpty(str1) || isStringEmpty(str2)||!str1.equals(str2))
{
return false;
}
return true;
}
}
4,用私有构造函数强化Singleton属性
第一种方式:
public class Elvis{
private static final Elvis INSTANCE = new Elvis();
private Elvis(){}
public static Elvis getInstance(){return INSTANCE;}
}
像之前说的那样,private构造函数使得该类不可实例化,同时public static的getInstance方法返回private static final的Elvis成员,而这个成员被final保证了只能实例化一次。
第二种方式:
public enum Elvis{
INSTANCE;
public void leaveTheBuilding(){……}
}
5,避免创建不必要的对象
// Creates lots of unnecessary duplicate objects - page 20-21 import java.util.*; public class Person {
private final Date birthDate; public Person(Date birthDate) {
// Defensive copy - see Item 39
this.birthDate = new Date(birthDate.getTime());
} // Other fields, methods omitted // DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
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;
}
}
改进为:
public class Person{
private Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static{
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(“GMT”));
//婴儿潮开始时间
cal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = cal.getTime();
//婴儿潮结束时间
cal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = cal.getTime();
}
//判断是否是婴儿潮出生的人
public boolean isBabyBoomer(){
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
}
}
可以看出,第一个Person类的isBabyBoomer方法会导致很多对象的创建,改进后使用static代码块,并将BOOM_START和BOOM_END设置为静态方法。这两个对象便只需对象new的时候创建一次。
6,消除过期的对象引用
一般而言,只要类是自己管理内存,程序员就应该警惕内存泄漏问题。一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。
这一条,还是需要结合具体应用场景和实例来谈才有意义。以后遇到类似问题再来补充。
书中的那个例子感觉挺蠢的,那个pop方法,正常人思维都是会释放其引用:
import java.util.*; public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
} public void push(Object e) {
ensureCapacity();
elements[size++] = e;
} public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
} /**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}