《Effective Java》第7章 方法

本章主要讨论方法设计的几个面:如何处理参数和返回值,如何设计方法签名,如何为方法编写文档。

1.检查参数的有效性 【Item 38】
1) 遵从“应该在发生错误之后尽快检查出错误”的原则,在方法的文档说明中应该写明传入参数的限制,并在方法开头处检查参数,强制判定参数是否符合限制,无效参数应该尽早检查出来,程序不必继续执行下去
2) 对于公有的方法,要用javadoc的@throws标签在文档中说明违反参数值限制时会抛出的异常
3) 用assert(断言)进行参数有效性检查,断言如果失败,将会抛出AssertionError,也不同于一般的有效性检查,如果它没有起到作用,本质上也不会有成本开销
4) 像构造器这种方法的参数主要是为了保存起来供以后使用的,那么检查构造器参数的有效性是非常重要的
5) 在方法执行它的计算任务之前,应该先检查它的参数,但有一种例外,当有效性检查工作非常昂贵,或者根本不切实际的,而且有效性检查已经隐含在计算过程中完成
6) 当然本条目并不是说对参数的任何限制都是好事
2.必要时进行保护性拷贝 【Item 39】
1) 假设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性地设计程序
2) 应该尽量设计一些面对客户端的不良行为时仍能保持健壮性的类
3) ,避免类的内部信息受到不合理的修改,保护不可变成员不被修改,对于构造器的每个可变参数进行保护性拷贝是必要的
4) 保护性拷贝是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是针对原始对象,多线程情况下避免拷贝过程中多线程的修改
5) 对于参数类型可以被不可信任方子类化的参数(非final类),请不要使用clone方法进行保护性拷贝
6) 访问方法和构造器不同,它们在进行保护性拷贝的时候允许使用clone方法,因为访问方法内部已知对象的类型不为某个潜在的不可信子类
7) 参数需要保护性拷贝的场景(原则是可变有风险就应该考虑):
a. 如果它允许客户端提供的对象进入到内部数据结构,一旦该对象在外部被改变可能影响内部数据结构
b. 不管类是否为不可变的,在把一个指向内部可变组件的引用返回给客户端之前,应该返回保护性拷贝,记住长度非零的数组总是可变的
8) 总之只要有可能,都应该使用不可变的对象作为内部的组件,这样就不必再为保护性拷贝操心
9) 如果类具有从客户端得到或者返回到客户端的可变组件,类就必须保护性拷贝这些组件,否则如果类信任它的客户端不会修改组件,那么应该在文档中指明客户端的职责是不得修改受到 影响的组件,以此来代替保护性拷贝
3.谨慎设计方法签名 【Item 40】
1) 谨慎地选择方法的名称,遵循命名习惯,容易理解,表达意图清晰,与已有命名风格一致
2) 不要过于追求提供便利的方法,不要总抽一堆方法,有必要才抽取方法,每个方法都应该尽其所能
3) 避免过长的参数列表,目标是四个参数,或者更少,相同类型的长参数序列格外有害,容易产生无意识错误并且不好排查,缩短过长参数列表的方法有:
a. 把方法分解成多个方法,每个方法只需要这些参数的一个子集
b. 创建辅助类,用一个helper类来包装一系列参数,用来保存参数的分组,该辅助类一般为静态成员类
c. 从对象构建到方法调用都采用Builder模式
4) 对于参数类型,要优先使用接口而不是类,这样容易扩大参数类型群,增加方法灵活性
5) 对于boolean参数,要优先使用两个元素的枚举类型,提升可读性,以及参数的扩展性,并可以利用枚举的类型特征,比如枚举常量的方法等
4.慎用重载 【Item 41】
1) 重载方法参数类型不要一样,或者有关联,那样容易出错
2) 对于运行时要调用哪个重载方法是在编译时做出的决定,因此对于重载(overloaded)方法的选择是静态的,而对于被覆盖(override)方法的选择是动态的
3) 覆盖机制是规范,而重载机制是例外,针对特殊需求设计,所以应该避免胡乱地使用重载机制
4) 安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法
5) 对于构造器你没有选择使用不同名称的机会,因此一个类的多个构造器总是重载的,对于构造器还不用担心重载和覆盖的互相影响,因为构造器不可能被覆盖
6) 基本类型的自动装箱和泛型成为java语言的一部分之后,谨慎重载显得更加重要,尤其注意自动装箱带来的影响
7) 数组类型和Object之外的类是截然不同的,数组类型和Serializable与Cloneable之外的接口也是截然不同的
8) 总之,能够重载的方法并不意味着就应该重载,即使要重载尽量避免同一组参数只需经过类型转换就可以被传递给不同的重载方法的情形,如果无法避免这种情形那么请保证当传递同样的参数时,所有重载方法的表现行为必须一致
5.慎用可变参数 【Item 42】
1) 可变参数方法是可以匹配不同长度的变量的方法,其接受0个或者多个指定类型的参数
2) 可变参数方法的每次调用都会导致进行一次数组分配和初始化
3) 不必改造具有final数组参数的每个方法,只当确实是在数量不定的值上执行调用时才使用可变参数
6.返回零长度的数组或者集合,而不是null 【Item 43】
1) 这样做可以减轻客户端Null chek的负担
2) 在未确认就是这样的做法影响了性能之前不这样做是不明智的
3) 对于不返回任何元素的调用,每次返回同一个零长度数组是有可能的,因为零长度的数组是不可变的,而不可变对象有可能被自由的共享
4) 返回类型为数组或集合的方法没理由返回null,而应该返回一个零长度的数组或者集合
7.为所有导出的API元素编写文档注释 【Item 44】
1) 代码的可维护性与文档注释息息相关
2) 为了正确的编写API文档,必须在每个被导出的类,接口,构造器,方法和域声明之前增加一个文档注释
3) 方法的文档注释应该简洁地描述出它和客户端之间的约定,说明这个方法是做了什么,而不是说明它是如何完成这项工作的,文档注释并且应该列举出这个方法的所有前置条件和后置条件
4) 每个方法还应该在文档说明中描述它的副作用,比如调用这个方法之后会起一个后台线程
5) 文档注释也应该描述类或者方法的线程安全性
6)为了完整的描述方法的约定,方法的文档注释应该包含一个@param标签,以及一个@return标签(除非这个方法返回类型为void),以及对于该方法抛出的每个异常,无论是受检的还是未受检的,都有一个@throws标签,按照惯例如上三个标签后面的短语或者句子都不用句点来结束
7) javadoc工具会把文档注释翻译成HTML,有的注释中含有code或者特殊符号,需要避免HTML的转义,那么就可以用javadoc{@code}标签,其避免了转义HTML元字符,而有时候只是插入> ,<或者&这种单个的HTML元字符不希望被转义,可以用{@literal}标签将其包围
8) 文档注释在源代码和产生的文档中都应该是易于阅读的,如果无法让两者都易读,产生的文档注释的可读性要优先于源代码的可读性
9) 同一个类或者接口中的两个成员或者构造器不应该具有同样的概要描述
10) 对于方法和构造器来说,概要描述应该是完整的动词短语,其描述了方法所执行的动作
11) 对于类,接口和域,概要描述应该是一个名词短语,其描述了该类或者接口的实例,或者域本身所代表的事物
12) 当为泛型或者方法编写文档时,确保要在文档中说明所有的类型参数
13) 当为枚举类型编写文档时,要确保在文档中说明常量,以及类型,还有任何公有的方法
14) 为注解类型编写文档时,要确保在文档中说明所有成员,以及类型本身
15) 类的线程安全性和可序列化性应该加入类的文档注释中
16) javadoc具有“继承”方法注释的能力,如果API元素没有文档注释,javadoc将会搜索最为使用的文档注释,接口的文档注释优先于超类的文档注释,也可以利用{@inheritDoc}标签从超类型中继承文档注释的部分内容
17) 为了降低文档注释的出错性,可使用HTML有效性检查器来对编写的文档注释进行校验,例如在校检验HTML[W3C-validator]
18) 对于多个互相关联的类组成的复杂API,通常有必要用一个外部文档来描述该API的总体结构,对文档注释进行补充(link)
19)编写文档注释的权威指导文档是sun公司的《How to Write Doc Comments》

阅读更多
换一批

没有更多推荐了,返回首页