第38条:检查参数的有效性
当编写方法或者构造器的时候,应该考虑它的参数有哪些限制。应该把这些限制写到文档中,并且在每个方法的开头处,通过显示的检查来实施这些限制。即应该在发生错误之后尽快检测出错误
,可以避免很多异常和不正确的却无法检测的结果。
通过进行有效性检查,付出的努力远远小于带来的异常。
例外
:有效检查工作非常昂贵。
但并不是意味着,对参数的任何限制都是好事,相反,在设计方法时候,应该使得他们尽可能通用,并符合实际的需要。然而在通常情况下,有的限制对被实现的抽象来说是固有的。
第39条:必要时进行保护性拷贝
- 设计安全的语言,需要加设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性地设计程序
- 对于每个构造器的每个可变参数进行保护性拷贝是必要的,注意,这个操作是在检查参数的有效性(见38)之前,并且有效性检查是针对拷贝之后的对象,不是针对原始的对象
- 对于参数类型可以被不可信任方子类化的参数,不要使用clone方法进行保护性拷贝
- 包括对传入的构造器的参数进行保护性拷贝,在内部组件返回给客户端,也需要保护性拷贝
总之:如果类具有从客户端得到或者返回到客户端的可变组件,类就必须保护性地拷贝这些组件。如果拷贝的成本收到限制,并且类信任它的客户端不会不恰当地修改足球,就可以在文档中指名客户端的职责是不得修改受影响的组件,以此来代替保护性拷贝
第40条:谨慎设计方法签名
- 谨慎选择方法的名称,始终遵循标准的命名习惯,与大众认可相一致
- 不要过于追求提供便利的方法。每个方法应该尽其所能,类中太多的方法难以学习,使用,文档化等,只有一个操作被使用的很频繁的时候,考虑为她提供快捷方式,否则不提供
- 避免过长的参数列表,小于等于4个。三种方法解决次问题,
- 分解方法成多个
- 用辅助类保存参数
- 从对象构架到方法调用采用Builder模式
- 参数类型,优先接口而不是类,boolean,优先使用两个元素的枚举类型(不是很明白
)
第41条:慎重重载
看下面的程序,
// Broken! - What does this program print?
public class CollectionClassifier {
public static String classify(Set<?> s) {
return "Set";
}
public static String classify(List<?> lst) {
return "List";
}
public static String classify(Collection<?> c) {
return "Unknown Collection";
}
public static void main(String[] args) {
Collection<?>[] collections = {
new HashSet<String>(),
new ArrayList<BigInteger>(),
new HashMap<String, String>().values()
};
for (Collection<?> c : collections)
System.out.println(classify(c));
}
}
我们期望的是打印Set,List, Unknown Collection,然后确实三次“Unknown Collection”
因为对于重载方法(overloaded method)的选择是静态(编译时)的,而对于覆盖(overriden method)的方法的选择是动态(运行时)的
- 应该避免胡乱地使用重载机制
- 安全而保守的策略,用于不要导出两个具有相同参数数目的重载方法,可以用不同的名称而不是重载。如果采用可变参数,则不要重载它
- 对于多个具有相同参数数目的方法来说,应该尽量避免重载,构造器往往不可避免,在此情况,要避免
这样的情形,同一组的参数只需要经过类型转换就可以被传递给不同的重载方法。如果不能避免,则要保证所有重载方法的行为一直。否则,程序员就很难有效利用,不理解为什么不能正常工作
第42条:慎用可变参数
可变参数方法可以接受0个或者多个指定类型的参数
// Simple use of varargs
static int sum(int... args) {
int sum = 0;
for (int arg : args)
sum += arg;
return sum;
}
有时候会有这样的需求,需要一个或者多个某种类型参数的方法,这时候需要指定一个正常参数和一个可变参数比较好
// The WRONG way to use varargs to pass one or more arguments!
static int min(int... args) {
if (args.length == 0)
throw new IllegalArgumentException("Too few arguments");
int min = args[0];
for (int i = 1; i < args.length; i++)
if (args[i] < min)
min = args[i];
return min;
}
因为可变参数的这个特性,我们可以讲数组当作final参数的现有方法,改造成可变参数代替,而不影响现有的客户端,然后可以并不意味着应该这么做,Arrays.asList就会出现不恰当的使用
对于:
public static void main(String[] args) {
int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
System.out.println(Arrays.asList(digits));
}
Arrays.asList将digits的对象引用包装到了List<int[]>中,而不是我们想要的那种每一个元素都包装,要想产生这种结果,可以这样:
// The right way to print an array
System.out.println(Arrays.toString(myArray));
因此 不必改造具有final数组参数的每个方法,只有当确实是在数量不顶的值上执行调用时使用可变参数
对于重视性能的程序来说,使用可变参数更要小心,如果某个方法的95%调用会有≤3个参数,则重载5个,超过了的用可变参数,如
public void foo() { }
public void foo(int a1) { }
public void foo(int a1, int a2) { }
public void foo(int a1, int a2, int a3) { }
public void foo(int a1, int a2, int a3, int... rest) { }
在定义参数数目不定的方法时,可变参数是一种很方便的方式,但是不能被滥用
第43条:返回零长度的数组或者集合,而不是null
返回null值会要求客户端中必须有额外的代码来处理null返回值,例如:
private final List<Cheese> cheesesInStock = ...;
/**
* @return an array containing all of the cheeses in the shop,
* or null if no cheeses are available for purchase.
*/
public Cheese[] getCheeses() {
if (cheesesInStock.size() == 0)
return null;
...
}
客户端需要:
Cheese[] cheeses = shop.getCheeses();
if (cheeses != null &&
Arrays.asList(cheeses).contains(Cheese.STILTON))
System.out.println("Jolly good, just the thing.");
}
而不是:
if (Arrays.asList(shop.getCheeses()).contains(Cheese.STILTON))
System.out.println("Jolly good, just the thing.");
返回数组也不必担心性能,因为0长度数组是不可变的,可以共享,在类中可以有一个static 的0长度数组来提供使用
如:
// The right way to return a copy of a collection
public List<Cheese> getCheeseList() {
if (cheesesInStock.isEmpty())
return Collections.emptyList(); // Always returns same list
else
return new ArrayList<Cheese>(cheesesInStock);
}
第44条:为所有到处的API元素编写文档注释
如果想要一个API真正可用,就必须为其编写文档。javadoc利用特殊格式的稳定注释(documentation comment),根据源代码自动产生API文档。
详细的规范可以参考:Sun的 How to Write Doc Comments
为了正确地编写API文档,必须在每个被到处的类,接口,构造器,方法和域声明之前增加一个文档注释。如果类是序列化的,也应该对它的序列化形式编写文档。
注意事项:
- @param、@return、@throws标签后面的短语或者子句都不用句点来结束。
- 使用html标签会被转换成HTML
- 使用代码片段放在{@code}中
- 特殊字符文档,比如小于号,放在{@literal}中
- 文档第一句话成注释所属元素的概要描述,因此要注意句点的使用
- 方法和构造器,概要最好是完整的动词短语,而类,接口和域,应该是名词短语
- 关于泛型,枚举和注解(后两者体验不深
)
- 为泛型或者方法编写文档,确保说明所以的类型参数
- 枚举,说明常量
- 注解,确保说明所有成员已经类型本身
简而言之:要为API编写文档,文档注释是最好的最有效的途径。
分享到:
相关推荐
"Effective Java读书笔记" Effective Java是一本关于Java编程语言的经典...Effective Java读书笔记总结了Java语言的发展历程、静态工厂方法的应用、构造器模式的使用等重要知识点,为Java开发者提供了有价值的参考。
《Effective Java》是Java开发领域的经典著作,作者Joshua Bloch深入浅出地阐述了编写高效、健壮的Java代码的技巧和最佳实践。以下是对该书部分内容的详细解释: 1. **产生和销毁对象** - Item1:静态工厂方法相比...
"Effective Java 读书分享" 《Effective Java》读书分享.pptx 是一本 Java 编程语言指南,旨在帮助开发者编写高质量、可维护的 Java 代码。该书包含 90 个条目,每个条目讨论一条规则,涵盖了 Java 编程语言的...
《Effective Java》是Java...以上仅是《Effective Java》一书中部分核心知识点的概述,实际的读书笔记中会更详细地解释这些概念,并给出具体的示例代码。通过深入学习和实践,开发者可以极大地提升其Java编程的水平。
根据给定的文件信息,以下是对“精版Effective STL读书笔记”的详细解析,重点提炼了STL(标准模板库)中的关键知识点。 ### 标题:“精版Effective STL读书笔记” 此标题暗示了文档是针对《Effective STL》一书的...
《Effective Java》是Java编程领域的一本经典著作,由Joshua Bloch撰写,该书的第三版继续提供了关于如何编写高效、优雅、可维护的Java代码的指导。以下是基于给出的目录和部分内容提取的一些关键知识点: ### 第一...
Effective Java 读书笔记 - 枚举与注解 本文总结了Effective Java 中关于枚举与注解的知识点,涵盖了枚举类型的优点、使用指南、避免使用 int 常量、使用 EnumSet 和 EnumMap 等。 枚举类型的优点 枚举类型提供了...
### Effective Java读书笔记(上) #### 第一章 引言 本书主要针对Java开发者提供了大量实用的编程指导建议,帮助读者提升代码质量和程序性能。在本章节中,我们将重点介绍对象的创建与销毁,以及一些重要的设计...
读书笔记:Effective Java中文版第3版笔记
读书笔记:Effective Java中文版 第2版
读书笔记:Effective Java中文版学习项目
读书笔记:Effective Java中文版第二版示例、笔记
读书笔记:Effective Java 中文版(2版和3版)
这本书的第三版包含了大量更新,涵盖了Java语言和平台的新发展,如Java 8和Java 9的新特性。以下是对《Effective Java》笔记中可能涉及的关键知识点的详细解读: 1. **单例模式**:书中强调了如何正确实现单例模式...
从给出的部分内容来看,读书笔记主要聚焦于以下几个知识点: 1. C++语言的联邦概念:C++是一个由多个次语言构成的语言联邦,这包括了C语言核心、面向对象的C++、模板C++以及标准模板库(STL)。这种理解对于深入...
读书笔记:Java练习包括《Java编程思想》《算法》《Effective Java》等
标题“effective-java.pdf”与描述“effective-java.pdf”表明本文档是关于Java编程实践的指南,且内容可能来自于一本名为《Effective Java》的书籍,该书是由Joshua Bloch编写,被广泛认为是Java编程的权威指南。...
读书笔记:Effective Java中文版第二版示例代码