Skip to content

Latest commit

 

History

History
72 lines (54 loc) · 5.92 KB

File metadata and controls

72 lines (54 loc) · 5.92 KB

Chapter 8. Methods(方法)

Item 49: Check parameters for validity(检查参数的有效性)

Item 50: Make defensive copies when needed(在需要时制作防御性副本)

Item 51: Design method signatures carefully(仔细设计方法签名)

  • 仔细选择方法名称
  • 不要提供过于便利的方法。 每种方法都应该各司其职。太多的方法使得类难以学习、使用、记录、测试和维护。
  • 避免长参数列表。 设定四个或更少的参数。长序列的同类型参数尤其有害。
    • 将方法分解为多个方法,每个方法只需要参数的一个子集
    • 创建 helper 类来保存参数组
      • 减少方法签名参数列表,提高可读性
      • 对象封装了相关字段,更清晰易理解
      • 可以给helper对象添加逻辑,比如校验
      • 以后修改参数不影响方法签名
    • 从对象构建到方法调用都采用建造者模式
  • 对于参数类型,优先选择接口而不是类
  • 双元素枚举类型优于 boolean 参数, 除非布尔值的含义在方法名中明确
    • boolean enabled;// true false 对比 enum Status{ENABLED, DISABLED}
    • 枚举可以添加更多的状态标志,有利于后续新增状态
    • 枚举见名知意,更具可读性

重载方法的选择是静态的,而覆盖法的选择是动态的 ,覆盖是规范,而重载是例外,应该避免混淆重载的用法。
方法可以重载,但并不意味着就应该这样做。通常,最好避免重载具有相同数量参数的多个签名的方法
安全、保守的策略是永远不导出具有相同数量参数的两个重载, 如果一个方法使用了可变参数,保守策略是根本不重载它。

在方法需要参数数量可变的情况下,可变参数是有效的。可变参数是为 printf 和经过改造的核心反射机制(Item-65)而设计的,它们与可变参数同时被添加到 JDK,printf 和 reflection 都从可变参数中受益匪浅.

使用可变参数会损失性能,因为每次调用可变参数都会导致数组分配和初始化

  • 解决方案: 假设你已经确定对方法 95% 的调用只需要三个或更少的参数。可以声明该方法的 5 个重载,每个重载 0 到 3 个普通参数,当参数数量超过 3 个时引入可变参数
  • EnumSet 的静态工厂使用这种技术将创建枚举集的成本降到最低。这是适当的,因为 enum 集合为位字段提供具有性能竞争力的替代方法是至关重要的

Item 54: Return empty collections or arrays, not nulls(返回空集合或数组,而不是 null)

永远不要用 null 来代替空数组或集合。它使你的 API 更难以使用,更容易出错,并且没有性能优势。
对于非集合类型的空对象则考虑使用Optional返回

并不是所有的返回类型都能从 Optional 处理中获益。容器类型,包括集合、Map、流、数组和 Optional,不应该封装在 Optional 中。 你应该简单的返回一个空的 List,而不是一个空的 Optional<List>

返回 Optional 并不是没有代价的。Optional 对象必须分配和初始化,从 Optional 对象中读取值需要额外的间接操作。这使得 Optional 不适合在某些性能关键的情况下使用。

永远不应该返包装类的 Optional , 除了「次基本数据类型」,如 Boolean、Byte、Character、Short 和 Float 之外
与返回基本数据类型相比,返回包含包装类的 Optional 类型的代价高得惊人,因为 Optional 类型有两个装箱级别,而不是零。
因此,库设计人员认为应该为基本类型 int、long 和 double 提供类似的 Optional。这些可选类型是 OptionalInt、OptionalLong 和 OptionalDouble

在集合或数组中使用 Optional 作为键、值或元素几乎都是不合适的

返回 Optional 会带来实际的性能后果;对于性能关键的方法,最好返回 null 或抛出异常。最后,除了作为返回值之外,你几乎不应该以任何其他方式使用 Optional

Item 56: Write doc comments for all exposed API elements(为所有公开的 API 元素编写文档注释)

  • 要正确地编写 API 文档,必须在每个公开的类、接口、构造函数、方法和字段声明之前加上文档注释
  • 方法的文档注释应该简洁地描述方法与其客户端之间的约定
    • 对于 unchecked 的异常,前置条件由 @throw 标记隐式地描述;@throw 标记后面的文本应该包含单词「if」,后面跟着一个描述抛出异常的条件的子句
    • 应该在文档中描述该方法产生的任何副作用,例如,如果一个方法启动了一个后台线程,文档应该说明
  • {@code} 标记有两个目的:它使代码片段以代码字体呈现,并且它抑制了代码片段中 HTML 标记和嵌套 Javadoc 标记的处理
    换句话说,在代码示例之前加上字符 <pre>{@code}</pre>
  • @implSpec 标记,当你为继承设计一个类时,你必须记录它的自用模式,以便程序员知道覆盖它的方法的语义
  • 文档注释应该在源代码和生成的文档中都具备可读性
  • 类或接口中的任何两个成员或构造函数都不应该具有相同的摘要描述
  • 为泛型类型或方法编写文档时,请确保说明所有类型参数
  • 编写枚举类型的文档时,一定要说明常量 以及类型、任何公共方法
  • 为注释类型的文档时,请确保说明全部成员 以及类型本身
  • 无论类或静态方法是否线程安全,你都应该说明它的线程安全级别
  • 如果一个类是可序列化的,你应该说明它的序列化形式