《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; }