一般在方法执行之前先检查参数的有效性,如果参数值无效,那么很快它就会失败,并且清楚的抛出合适的异常。
如果这个方法没有检查参数的异常,那么可能在方法处理中出现令人费解的异常。更糟糕的有可能是,方法可以正常返回,但是却使得某个对象处于被破坏的状态。
对于公有方法,可以在Javadoc中的@throw标签来说明违反异常时所抛出的异常类型。一旦在文档中说明了异常,那么强加这些类型的异常检测就会是比较容易的事情。
另外,对于未被导出的方法,作为包的创建者,你可以控制这个方法在哪些情况下可以被调用,因此你可以,也应该确保只将有效的参数传递进去。因此,非公有方法通常应该使用断言(assert)来检查它们的参数。
在生产环境中,一般是不支持assert的,因此这样可以提高效率,没有成本开销。所以,assert只在私有方法中使用,因为私有方法的调用者开发者,他和被调用者之间是一种弱契约关系,或者说没有契约关系,其间的约束是依靠开发者自己控制的,开发者应该有充分的理由相信自己传入的参数是有效的。所以,从某种角度上来说,assert只是起到一个预防开发者自己出错,或者是程序的无意出错。
尽管在构造器中检查参数的有效性非常必要,但是也有例外,可能在有效情况下检查参数的有效性是及其昂贵的,甚至是不切实际的。比如说,Collections.sort(list)。列表中的所有对象都是可以比较的。在排序过程中会自动检查这些参数的有效性,而并不是在构造的时候检查参数的有效性。
并非对参数的任何限制都是好事,一般来说要尽可能的通用, 符合实际的需要。假如方法对它能接受的参数都能完成合理的计算,那么对于参数的限制其实是越少越好的。因此,鼓励开发者把限制写到文档中,并在方法的开头显式的检查参数的有效性。
Java是一门安全的语言,它对于缓冲区溢出、数组越界、非法指针以及其他的内存破坏错误都自动免疫。
参数的保护性拷贝不仅仅局限于不可变类,每当编写方法和构造器的时候,如果允许客户端提供的对象进入到内部的数据,就需要考虑,客户端的对象是否是可变,它的可变是否会对内部数据产生影响。
如同上面第二种方式,当内部数据返回客户端的时候,同样需要考虑这个问题,是否需要返回内部数据的保护性拷贝。一般来说,将内部引用返回给客户端的时候,都需要进行保护性拷贝(见13条)。
因此,只要有可能,都应该使用不可变对象作为对象的内部组件,这样就不必进行保护性拷贝了。常常,程序员会使用Date.getTime()返回的long类型作为内部的时间表示法,因为Date是可变的。
本条目是若干API设计技巧的总结,这些设计技巧将有助于使你的API更易于学习和使用,并且不容易出错。
对于参数类型,要优先使用接口而不是类。
对于boolean参数,要优先使用两个元素的枚举类型。
对于重载方法的选择是静态的,也即调用哪个重载方法是在编译时做出的决定,而对于被覆盖的方法的选择则是动态的,选择被覆盖的方法的正确版本是在运行时进行的,选择的依据是被调用方法所在对象的运行时类型。
因为覆盖机制是规范,而重载机制是例外,所以,覆盖机制满足了人们对于方法调用行为的期望。
安全保守的策略是,永远不要到处两个具有相同参数数目的重载方法。如果方法使用可变参数,保守的策略是根本不要重载它。
可变参数方法接受0个或者多个指定类型的参数。可变参数机制通过先创建一个数组,数组的大小为在调用位置所传递的参数数量,然后将参数值传递到数组中,最后将数组传递给方法。
当你真正需要让一个方法带有不定数量的参数时,可变参数就非常有效。
在重视性能的情况下,使用可变参数机制要特别小心,可变参数方法的每次调用都会导致进行一次数组分配和初始化。所以它们不应该被过度滥用。
返回类型为数组或集合的方法没理由返回null,而是返回一个零长度的数组或者集合。
如果要想使一个API真正可用,就必须为其编写文档。Javadoc利用特殊格式的文档注释,根据源码自动产生API文档。
为了正确地编写API文档,必须在每个被导出的类、接口、构造器、方法和域声明之前增加一个文档注释。如果类是可序列化的,也应该对它的序列化形式编写文档。
方法的文档注释应该简洁地描述出它和客户端之间的约定。
为了完整的描述方法的约定,方法的文档注释应该让每个参数都有一个@param标签,以及一个@return标签,以及对于该方法抛出的每个异常,无论是受检的还是未受检的,都有一个@throws标签。
当为枚举类型编写文档时,要确保在文档中说明常量,以及类型,还有任何公有的方法。
为注解类型编写文档时,要确保在文档中说明所有成员,以及类型本身。
关于编写文档注解最权威的指导是Sun公司的《How to Write Doc Comments(如何编写文档注释)》。