第5章 方法(Methods)
19 检查参数合法性(Check parameters for validity)
应该尽早的检查错误。
对公共的方法,使用Javadoc的@throws标签来说明如果对参数值的约束被违反时将抛出什么异常。
对于非公共的方法,通常使用断言来检查参数。
对于那些把参数存起来以备后续使用的方法来说,检查参数的合法性尤其重要。否则会使得调试工作更加复杂。
更加重要的是检查构造函数的参数的合法性,以防止构造出违背类不变性的对象。
如果参数的合法性检查代价非常高或是不实际并且合法性检查在计算过程中被隐含执行的话,就不需要检查了。
在某些情况下,计算过程中会隐含执行类型检查,当时会抛出类型不正确的异常。这个时候就需要采用类型转换技术(在Item 43中描述)。
20 需要时进行防御性复制(Make defensive copies when needed)
你必须防御性的编程,假定使用你的类的客户会尽其所能的破坏类的不变性。
必须对构造函数的每个可变的参数进行防御性复制。
防御性复制在检查参数合法性之前进行,并且合法性检查是对副本进行的。
不要使用可以被不信任的团体子类化的类型的clone方法进行防御性复制。
返回可变的内部数据域的防御性副本。
非零长度的数组总是可变的,因此在返回给客户一个内部数组之前,要进行防御性复制。
21 仔细的设计方法的型构(Design method signatures carefully)
仔细选择方法的名称。
不要过于追求提供便捷方法。(Don’t go overboard in providing convenience methods)
避免长的参数列表。3个就是实际中最长的了。长序列的类型相同的参数更加有害。
解决参数过多的两种方法:一是把方法分解成多个方法,二是创建帮助类来把某些参数聚集起来。
对于参数类型,优先使用接口而不是类。
谨慎使用函数对象。
22 谨慎使用overloading
当函数被overloading之后,选择哪个方法执行是在编译时刻确定的。选择overloaded方法是静态的,但是选择overridden方法是动态的。Overloading的方法运行时的类型并不影响哪个方法被执行,选择是在编译时刻做出的,完全取决于编译时刻的参数类型。
一种安全的策略是决不暴露出参数个数相同的overloading方法。
比如Java类库种的ObjectOutputStream的方法,不是采用的overloading其中的write方法,还是有writeInt(int), writeLong(long)等方法。
最好保证overloading的方法中至少有一个形式参数的类型显著不同,以方便使用者区分。
23 返回长度为0的数组,而不要返回空值(Return zero-length arrays, not nulls)
private List cheesesInStock = … ;
private final static Cheese[] NULL_CHEESE_ARRAY = new Cheese[0];
public Cheese[] getCheeses() {
return (Cheese[]) cheesesInStock.toArray(NULL_CHEESE_ARRAY);
}
24 为所有的输出API元素书写文档注释(Write doc comments for all exposed API elements)
在每个输出的类,接口,构造函数,方法和域的声明之前添加文档注释。
方法的文档注释应该简洁的描述方法及其客户之间的合约。