1. 构造函数一定不能调用可被覆写的方法,无论是直接还是间接进行。
2. 接口应该只是被用来定义类型的,它们不应被用来导出常量。(备注:不要再接口中定义常量)
3. 一个安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法。
4. 返回零长度的数组而不是null。
5. 嵌套类
嵌套类(nested class)是指被定义在另一个类的内部的类,其存在的目的应该只是为它的外围类提供服务。嵌套类分为四种:
5.1 静态成员类(static member class)
最简单的嵌套类,最好把它看做一个普通的类。它可以访问外围类的所有成员,包括那些声明为私有的成员。与其他类静态成员一样,也遵守同样的可访问性规则。
其通常用法是作为公有的辅助类,仅当与它外部类一起使用时才有意义。
私有静态成员类的一种通常用法是用来代表外围类对象的组件。例如,Map实例的内部通常有一个Entry对象对应与Map中每一对键值对,虽然每一个Entry都与一个Map关联,但Entry上的方法(getKey、getValue、setValue)并不需要访问该Map。因此使用非静态成员来表示Entry是浪费的,私有静态成员类是最佳的选择。
5.2 非静态成员类(nonstatic member class)
非静态成员类的每一个实例都包含一个额外指向外部类对象的引用。维护这份引用要消耗时间和空间。
其通常用法是定义一个Adapter,它允许外围类的一个实例被看做另一个不相关的类的实例。例如,Map接口的实现往往使用非静态成员类来实现它们的集合视图。
5.3 匿名类(anonymous class)
没有名字,它不是外围类的一个成员,在使用的同时被声明和实例化。可以出现在代码中任何允许表达式出现的地方。通常只实现了其接口中或超类中的方法,不会声明任何新的方法,它们应该非常简短。
用法1 是创建一个函数对象(function object),比如Comparator实例。例如:
Arrays.sort(args,new Comparator<String>() {
@Override
public int compare(String obj1, String obj2) {
return obj1.length() - obj2.length();
}
});
用法2 创建一个过程对象(process object),比如Thread、Runable或者TimeTask实例。
用法3 在一个静态工厂方法的内部,如:
static List intArrayList(finalint[] a){
return new AbstractList<Integer>() {
@Override
public Integer get(int location) {
return a[location];
}
@Override
public int size() {
return a.length;
}};
}
用法4 在复杂的类型安全枚举类型中,用于公有的静态final域的初始化器中,例如:
public abstract class Operation {
private final String name;
Operation(String name) {
this.name = name;
}
public String toString() {
returnthis.name;
}
abstract double eval(double x,double y);
public static final Operation PLUS =new Operation("+") {
@Override
double eval(double x,double y) {
return x + y;
}
};
}
5.4 局部类(local class)
使用最少,在任何“可以声明局部变量”的地方,都可以声明局部类,也遵守同样的作用域规则。与匿名类一样,它们必须非常简短。
简而言之,如果一个嵌套类需要在单个方法之外仍然是可见的,或者它太长了,不适合放在一个方法内部,那么应该使用成员类。如果成员类的每个实例都需要一个指向其外围实例的引用,则把成员类做成非静态的;否则就做成静态的。假设一个嵌套类属于一个方法的内部,如果你只需要在一个地方创建它的实例,并且已经有了一个预先存放的类型可以说明这个类的特征,则把它做成匿名类;否则就做成局部类。
6. 了解和使用库
应该熟悉java.lang、java.util以及java.io中的内容。
6.1 Random.nextInt(int) 产生随机整数。
6.2 Collections.sort(v) 字符串组成的Vector排序
6.3 Collections.sort(v, String.CASE_INSENSITIVE_ORDER) 字符串组成的Vector排序,忽略大小写
6.4 System.out.println(Arrays.asList(a)) 循环打印一个数组中所有的元素
6.5 获取两个Hashtable包含相同映射键值的所有键:
Map tmp =new HashMap(h1);
tmp.entrySet().retainAll(h2.entrySet());
Set result = tmp.keySet();
6.6 Arrays.toString(a) 打印数组每一个元素
6.7 Arrays.equals(a1, a2) 比较两个数组长度、每一个元素是否相等。
7. 使用异常
7.1 被检查的异常(checked exception)
通过抛出一个被检查的异常,强迫调用者在一个catch子句中处理异常,或者将它传播到外面。
7.2 运行时异常(run-time exception)
大多数的运行时异常都是指API的客户没有遵守API规范建立的约定。例如数组越界。
总而言之,对于可恢复的条件,使用被检查的异常;对于程序错误,使用运行时异常。
8. 尽量使用标准的异常
8.1 IllegalArgumentException 调用者传递的参数不合适
8.2 NullPointException 空指针异常
8.3 IndexOutOfBoundsException 下标越界
8.4 ConcurrentModificationException 在禁止并发修改的情况下,对象检测到并发修改
8.5 UnsupportedOperationException 对象不支持所请求的方法