Effective Java 读书笔记(六):方法
来源:互联网 发布:js正则表达式 冒号 编辑:程序博客网 时间:2024/05/29 08:00
- Effective Java 读书笔记六方法
- 检查参数的有效性
- 必要时进行保护性拷贝
- 谨慎设计方法签名
- 慎用重载
- 慎用可变参数
- 返回零长度的数组和集合而不是 null
- 为所有导出的 API 元素编写文档注释
Effective Java 读书笔记(六):方法
检查参数的有效性
绝大多数方法和构造器对于传递给它们的参数都会有某种限制,你应该在文档中清楚地指明所有这些限制,并且在方法体的开头处检查参数,以强制施加这些限制。这是“应该在发生错误之后,尽快检测出错误”这一普遍原则的一个具体情形。如果不能做到这一点,检测到错误的可能性就比较小,即使检测到错误了,也难以确定错误的根源。不做参数检查有什么危害呢?
1. 该方法可能在处理过程中失败,并且产生令人费解的异常。
2. 更糟糕的是,方法正常返回,但计算出了错误的结果。
3. 最糟糕的是,方法正常返回,但却使某个对象处于被破坏的状态,使得将来在某个不确定的时候,在不相关的点上引发错误。
对于公有的方法,要用 Javadoc 的 @throws 标签在文档中说明,如果违反了参数值限制时,会抛出哪些异常,比如 IllegalArgumentException、IndexOutOfBoundsException 或 NullPointerException。
必要时进行保护性拷贝
如果类具有从客户端得到或返回到客户端的可变组件,类就必须保护性地拷贝这些组件。如果拷贝的成本受到限制,并且类信任它的客户端不会不恰当地修改组件,就可以在文档中指明“客户端的职责是不得修改受到影响的组件”,以此来代替保护性拷贝。
public final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { if (start.compareTo(end) > 0) { throw new IllegalArgumentException(start + " after " + end); } this.start = start; this.end = end; } public Date start() { return start; } public Date end() { return end; }}
对于 Period 类来说,由于 Date 类是可变的,导致虽然 Period 没有 set 之类的修改方法,也很容易篡改其字段的值。故而,适当的保护性拷贝是必要的。
public final class Period { private final Date start; private final Date end; // 构造方法保护性拷贝 public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (this.start.compareTo(this.end) > 0) { throw new IllegalArgumentException(this.start + " after " + this.end); } } // 读方法保护性拷贝 public Date start() { return new Date(start.getTime()); } public Date end() { return new Date(end.getTime()); }}
上面构造方法中,参数检查必须在保护性拷贝之后,这是为了避免 Time-Of-Check/Time-Of-Use 攻击。
谨慎设计方法签名
这里是一些设计易学、易用 API 的技巧:
- 谨慎选择方法名称:遵循命名习惯、项目风格。
- 方法不要太多,太多了难以维护。
- 避免过长的参数列表。一般多于 4 个参数,就容易让人记不住。如果参数很多时,怎么办?
- 分解方法成多个。
- 使用辅助类,将多个参数封装到一个方法中。
- 从对象构建到方法调用都采用 Builder 模式。
- 对于参数类型,要优先使用接口,而非类。比如一般都用 Map,而不用 HashMap。
- 对于 boolean 参数,优先使用枚举类型(如果这个参数后续可能扩展其他值的话)。
慎用重载
对于以下类会输出什么呢?答案是 collection。因为具体要调用哪个重载 overloading 方法是在编译时做出决定的,而调用哪个覆盖 override 方法是在运行时做出决定的。
public class Test { public static String name(Set<?> set) { return "set"; } public static String name(List<?> list) { return "list"; } public static String name(Collection<?> collection) { return "collection"; } public static void main(String[] args) { Collection<Integer> collection = Lists.newArrayList(); System.out.println(name(collection)); }}
如果两个重载方法的参数个数相同,就要小心了,最好避免这种情况,减少误用。
慎用可变参数
可变参数有什么问题呢?
1. 需要创建数组,数组耗费性能,不适合性能要求极高的程序。
2. 可能需要额外检查传 0 个参数的情况。
3. 举例来说,在 Arrays.asList 方法中,传递 int[] 对象时,无法正常工作,该方法会把整个 int[] 当初 List 的第一个元素。
返回零长度的数组和集合,而不是 null
返回 null 就需要让调用方去做额外的判断(这很容易被遗忘),同时也让代码变得臃肿。如果担心返回空数组或集合影响性能的话,可以将空数组或集合做成常量,这正是 Collections 的 emptyList、emptyMap 方法所提供的功能。
为所有导出的 API 元素编写文档注释
为了正确地编写 API 文档,必须在每个被导出的类、接口、构造器、方法和域声明之前增加一个文档注释。为了编写可维护的代码,还应该为那些没有被导出的类、接口等等编写注释。
方法的文档注释应该简洁地描述出它和客户端之间的约定。具体描述什么呢?
1. 前提条件:客户端调用方法必须满足的条件。
2. 后置条件:调用成功之后,哪些条件会被满足。
3. 副作用:系统状态中可以观察到的变化,它不是为了获得后置条件而明确要求的变化。
4. 是否线程安全?是否可序列化?
5. @param 标签说明参数。
6. @return 说明返回值。
7. @throws 说明什么情况下,抛出哪些异常?
8. 每个文档注释的第一句话,成为注释所属元素的概要描述。
9. 对于泛型、注解、枚举这些特殊类型,也有用文档描述其中的类型参数、成员变量、常量。
10. 如果多个 API 之间有关联,那应该有一个总的文档来描述这组 API 的总体结构。
关于编写文档的指导,可以查看如何写Java文档注释。
- Effective Java 读书笔记(六):方法
- Effective Java读书笔记六:方法
- Effective Java读书笔记(六)
- Effective Java读书笔记六:方法(38-44)
- Effective Java读书笔记六
- effective java读书笔记六
- effective C++读书笔记(六)
- 【读书笔记】《Effective Java》(6)--方法
- 【effective Java读书笔记】方法(一)
- 【effective Java读书笔记】方法(二)
- 【effective Java读书笔记】方法(三)
- More Effective C++读书笔记(六)
- Effective C++ 读书笔记六
- effective c++ 读书笔记(六)
- Effective Java读书笔记(第7章-方法)
- 十月读书笔记:Effective Java(五)--clone和toString方法
- Effective.Java 读书笔记(1)静态工厂和构造方法
- Effective.Java 读书笔记(8)关于equals方法
- 网易2018校园招聘编程题真题-[编程题] 魔法币
- 观察者模式(一)
- python第三方库之numpy
- 【SHOI2012】魔法树
- 网页xx秒将返回测JS代码的实现
- Effective Java 读书笔记(六):方法
- 5-预定义变量的使用
- 静态链表的基本操作实现
- 使用Aspose.Cells.dll导出数据到Excel
- orm与数据持久化
- model1(jsp+javaBean)和model2(jsp+servlet+javaBean+MVC)开发模式优缺点
- Unable to resolve target 'android-17'解决方法
- <Web>jQuery黑客帝国,数字下落特效!
- 【LeetCode】Identical Binary Tree等价二叉树