第八章 方法

第四十九条:检查参数的有效性

对于公有的和受保护的方法,要用Javadoc的@throw标签在文档中说明违反参数值限制时会抛出的异常。

在Java 7 中增加的Objects.requireNonNull方法比较灵活且方便,因此不必要再手工进行null检查。

在方法执行他的计算任务之前,应该先检查他的参数,这一规则也有例外。一个很重要的例外是,在某些情况下,有效性检查工作非常昂贵,或者根本是不切实际的,而且有效性检查已隐含在计算过程中完成。然而,不加选择的使用这种方法将会导致失去失败原子性。

有时候,某些计算会隐式的执行必要的有效性检查,但是如果检查不成功,就会抛出错误的异常。换句话说,由于无效的参数值而导致计算过程抛出的异常,与文档中标明这个方法将抛出的异常并不相符。在这种情况下,应该使用第73条中讲述的异常转换技术,将计算过程中抛出的异常转换为正确的异常。

在设计方法时,应该使他们尽可能通用,并符合实际的需要。假如方法对于它能接受的所有参数值都能够完成合理的工作,对参数的限制就应该是越少越好。然而通常情况下,有些限制对于被实现的抽象而言是固有的。

第五十条:必要时进行保护性拷贝

假设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性的设计程序。

Date已经过时了,不应该在新代码中使用。

为了保护实例的内部信息避免受到这种攻击,对于构造器的每个可变参数进行保护性拷贝是必要的,并且使用备份对象作为实例的组件,而不使用原始的对象。

保护性拷贝是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是针对原始的对象。

对于参数类型可以被不可信任方子类化的参数,请不要使用clone方法进行保护性拷贝。

为了防止访问方法对内部成员的访问导致的实例的改变,可以使它返回内部域的保护性拷贝。

如果类包含的方法或者构造器的调用需要移交对象的控制权,这个类就无法让自身抵御恶意的客户端。

第五十一条:谨慎设计方法签名

谨慎的选择方法的名称。方法的名称应该始终遵循标准的命名习惯。首先应该选择易于理解的,并且与同一个包中的其他名称风格一致的名称。应该选择与大众认可的名称相一致的名称。

不要过于追求提供便利的方法。如果不能确定,对号不要提供快捷方式。

避免过长的参数列表。目标是四个参数或者更少。相同类型的长参数序列而格外有害。

缩短过长参数列表的技巧:
把一个方法分解成多个方法,每个方法只需要这些参数的一个子集。
创建辅助类,用来保存参数的分组。
从对象构建到方法调用都采用Builder模式。

对于参数类型,要优先使用接口而不是类。只要有适当的接口可用来定义参数,就优先使用这个接口,而不是使用实现该接口的类。

对于Boolean参数,要优先使用两个元素的枚举类型。

第五十二条:慎用重载

要调用哪个重载方法是在编译时做出决定的。

对于重载方法的选择是静态的,而对于被覆盖的方法的选择是动态的。

与重载的情形相比,对象的运行时类型并不影响“哪个重载版本将被执行”;选择工作时在编译时进行的,完全基于参数的编译时类型。

应该避免胡乱的使用重载机制。

安全而保守的策略是,永远不要导出两个具有相同参数数目的重载方法。

始终可以给方法起不同的名称,而不使用重载机制。

不要在相同的参数位置调用带有不同函数接口的方法。

第五十三条:慎用可变参数

可变参数机制首先会创建一个数组,数组的大小为在调用位置所传递的参数数量,然后将参数值传到数组中,最后将数组传递给方法。

这种方案有几个问题:如果客户端调用这个方法时,并没有传递参数进去,他就会在运行时而不是编译时发生失败。而且这段代码很不美观。

解决方案:声明该方法带有两个参数,一个是指定类型的正常参数,另一个是这种类型的可变参数。

在重视性能的情况下,使用可变参数机制要特别小心。每次调用可变参数方法都会导致一次数组分配和初始化。如果凭借经验确定无法承受这一成本,但又需要可变参数的灵活性,还有一种模式可以让你如愿以偿。假设确定对某个方法95%的调用会有三个或者更少的参数,就声明该方法的5个重载,每个重载方法带有0-3个普通参数,当参数的数目超过3个时,就使用一个可变参数方法。当参数的数目超过3个时,所有调用只有5%需要创建数组。

Enum类对他的静态工厂使用了这种方法,最大限度的减少创建枚举集合的成本。当时这么做是有必要的,因为枚举集合为位域提供了在性能方面有竞争力的替代方法,这是很重要的。

第五十四条:返回零长度的数组或者集合,而不是null

返回null而不是零长度的容器,也会使返回该容器的方法实现代码变得更加复杂。

Null返回值比零长度集合或者数组更好,因为它避免了分配零长度的容器需要的开销,这种观点是站不住脚的。原因有二:第一,在这个级别上担心性能的问题是不明智的,除非分析表明这个方法正是造成性能问题的真正源头。第二,不需要分配零长度的集合或者数组,也可以返回他们。

万一有证据表示分配零长度的集合损害了程序的性能,可以通过重复返回一个不可变的零长度集合,避免了分配的执行,因为不可变对象可以被自由共享。

第五十五条:谨慎返回optional

永远不要通过返回optional的方法返回null。因为它违背了optional的本意。

Optional本质上与受检异常相类似,因为他们强迫API用户面对没有返回值的现实。

如果方法返回optional,客户端必须做出选择,如果该方法不能返回值时应该采取什么动作,你可以指定一个缺省值,或者抛出任何适当的异常。如果能证明optional为非空,就不必指定如果optional为空要采取什么动作,直接optional获得值即可,如果你的判断错了,代码就会抛出一个NoSuchElementException。

有时候,获取缺省值的开销可能很高,除非十分必要,否则还是希望能够避免这一开销。对于这类情况,Optional提供了一个带有Supplier的方法,只在必要时才调用它。这个方法叫orElseGet。

万一这些方法都无法满足需求,Optional还提供了isPresent()的方法,它可以被当作一个安全阀。

容器类型包括集合、映射、Stream、数组和optional,都不应该被包装在optional中。

如果无法返回结果并且没有返回结果时客户端必须执行特殊的处理,那么就应该声明该方法返回Optional。

永远不应该返回基本包装类型的optional,“小型的基本类型”除外。

几乎永远都不适合用optional作为键、值,或者集合或数组中的元素。

第五十六条:为所有导出的API元素编写文档注释

为了正确的编写API文档,必须在每个被导出的类、接口、构造器、方法和域声明之前增加一个文档注释。

方法的文档注释应该简洁的描述出他和客户端之间的约定。

文档注释应该列举出方法的所有前提条件和后置条件,所谓前提条件是指为了使客户能够调用这个方法,而必须满足的条件,所谓后置条件是指在调用成功完成之后,哪些条件必须要满足。除了前提条件和后置条件之外,每个方法还应该在文档中描述他的副作用,即系统状态中可以观察到的变化,他不是为了获得后置条件而明确要求的变化。

文档注释在源代码和产生的文档中都应该是易于阅读的。如果无法让两者都易读,产生的文档的可读性要优先于源代码的可读性。

同一个类或者接口中的两个成员或者构造器,不应该具有同样的概要描述。

当为泛型或者方法编写文档时,确保要在文档中说明所有的类型参数。
当为枚举类型编写文档时,要确保在文档中说明常量,以及类型,还有任何公有的方法。
为注解类型编写文档时,要确保在文档中说明所有成员,以及类型本身。
类或者静态方法是否安全,应该在文档中对他的线程安全级别进行说明。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值