论坛首页 Java企业应用论坛

Effective java学习笔记(一)

浏览 2763 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (9) :: 隐藏帖 (3)
作者 正文
   发表时间:2010-09-13   最后修改:2010-09-14
1:使用私有构造函数强化singleton属性
实现singleton有两种方法,这两种方法都要把构造函数保持为私有,并且提供一个静态成员,以便允许客户能够访问该类唯一的实例
private static final SingletonTest instance = new SingletonTest(); 
private SingletonTest() {   
        System.out.println("SingletonTest Constructor...");   
}

public static SingletonTest getInstance() {     
        return SingletonCreate.instance;     
}

2:改写equals时总是要改写hashCode
在每个改写了equals方法的类中必须要改写hashCode方法。如果不这样做,就会违反object.hashCode的通用约定,从而导致该类无法与基于散列值(hash)的集合类结合在一起正常运作,这样的集合类包括HashMap,HashSet,Hashtable。

1:在一个应用程序期间,如果一个对象的equals方法作比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,它必须始终如一返回同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
2:如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中的任何一个对象的hashCode方法必须产生同样的整数结果。
3:如果两个对象根据equals(Object)方法是不想等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果。
private final short areaCode;
	private final short exchange;
	private final short extension;
	
	public HashCodeTest(int areaCode,int exchange,int extension){
		rangeCheck(areaCode, 999, "area code");
		rangeCheck(exchange, 999, "exchange");
		rangeCheck(extension, 9999, "extension");
		this.areaCode=(short)areaCode;
		this.exchange=(short)exchange;
		this.extension=(short)extension;
	}
	
	private static void rangeCheck(int arg,int max,String name){
		if(arg<0 || arg> max)
			throw new IllegalArgumentException(name+";"+arg);
	}
public static void main(String[] args) {
	Map m=new HashMap();
	m.put(new HashCodeTest(408,867,5309), "hawk7");
	System.out.println(m.get(new HashCodeTest(408,867,5309)));
	System.out.println(new HashCodeTest(408,867,5309).equals(new 							HashCodeTest(408,867,5309)));
	}

在没有实现equals和hashCode方法时一个返回null,另一个返回false
实现equalse方法没实现hashCode方法 返回null和true;
两个都是先返回hawk7和true;
引用
如果只需要关心域中的值是否相等,则需要实现equals方法,同时必须实现hashCode方法

3:总是要改写toString方法,可借助工具类,例如:
public String toString() {   
        ToStringBuilder builder = new ToStringBuilder(this);   
        builder.append("id", id).append("name", name);   
        return builder.toString();   
}  

4:使类和成员的可访问能力最小化
应该尽可能的使每一个类或者成员不被外界访问
5:复合优先于继承
只有当子类和超类之间确实存在了子类型关系时,使用继承才是恰当的,如果子类和超类在不同的包中,而且包类并不是为扩展而设计,那么就该使用复合或者转发机制代替继承
6:接口只是被用于定义类型
当一个类实现了一个接口的时候,这个接口被用作一个类型(type),通过此类型可以引用这个类的实例,因此一个类实现了一个接口就表明客户可以对这个类的实例进行某些动作,为了任何其它目的而定义接口是不合适的
引用
常量接口模式是对接口的不良使用

7:检查参数的有效性
对于公有的方法使用javadoc @throws标签tag可以是文档中记录下"一旦针对参数值的限制被违反之后 将会抛出的异常"
	public BigInteger getAAA(BigInteger x){
		if(x.signum()<=0)
			throw new ArithmeticException();
	}

非公有的方法通常应该使用断言(assertions)来检测它们的参数,而不使用正常的检查语句
8:不要追求提供便利的方法:每一个方法应该提供其应具备的功能点
9:避免太长的参数列表
10:参数类型优先使用接口而不是类
例如:没有理由编写一个方法时使用hashMap作为输入,应该使用map
11:返回0长度的数组而不是null
12:如果要求精确的答案,请避免使用float和double。
eg:
System.out.println(1.03-.42);

输出:
0.6100000000000001

正确的办法应该是使用BigDecimal,int,long。
如果是希望系统处理十进制小数点,并且不介意因为不使用原语类型而带来的不便,那么就是用BigDecimal。使用BigDecimal允许你完全控制舍入。如果性能十分关键,自己又不愿意去处理十进制小数点,而且送涉及的数字又不是很大,则使用int或者long.如果数值范围没有超过9位十进制数,则使用int.如果不超过18位数字,则可以使用long。如果数值范围超过了18位,则就必须使用BigDecimal。
13:只有针对不正常的条件才使用异常。
eg:
try{
			int i=0;
			while(true)
				a[i++].f();
		}catch(ArrayIndexOutOfBoundsException e){
			
		}

for(int i=0;i<a.length;i++){
			a[i].f();
		}

有人会优先使用基于异常的模式,这其实被误导了。他们企图利用java的错误判断机制来提高性能。因为JVM对数组的每次访问都要检查是否越界,所以他们认为循环终止测试时多余的。这种想法是错误的。必须认识到如下:
异常机制的设计初衷是用于不正常的情形,很少会有JVM实现试图对他们的性能做优化。所以创建,抛出,和捕获异常的开销是昂贵的。
对数组进行遍历的标准模式并不会导致冗余的检查,有些现代的JVM实现会将它们优化掉。
引用
异常永远不应该被用于正常的控制流
   发表时间:2010-09-16  
非常不错,学习了,期待LZ的后续
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics