第38条: 检查参数的有效性

对于这一条,最常见的莫过于检查参数是否为null。

有时出现调用方未检查传入的参数是否为空,同时被调用方也没有检查参数是否为空,结果这就导致两边都没检查以至于出现null的值程序出错,通常情况下会规定调用方或者被调用方来检查参数的合法性,或者干脆规定都必须检查。null值的检查相当有必要,很多情况下没有检查值是否为空,结果导致抛出NullPointerException异常。

除了null,常见的还有对于方法参数的限制。一个典型的例子:

public BigInteger mod(BigInteger m) {
if (m.signum <= 0)
throw new ArithmeticException("BigInteger: modulus not positive"); BigInteger result = this.remainder(m);
return (result.signum >= 0 ? result : result.add(m));
}

总之,每当编写方法或构造器时,应该考虑它的参数有哪些限制,应该把这些限制写到文档中去,并且在这个方法的开头处,通过显示的检查来实施这些限制。

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

java是一门安全的语言,但即使在安全的语言中,如果不采取点措施,还是无法与其它的类隔离开来。假设类的客户端会尽其所能来破坏这个类的约束条件,因此必须保护性地设计程序。考虑下面的类,表示一段不可变的时间周期。

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;
}
@Override
public String toString() {
return start + " -- " + end;
}
public static void main(String[] args){
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
System.out.println(p);
end.setYear(78);
System.out.println(p);
}
}

从输出语句来看,这个“不可变的时间周期”变了。虽然私有域start和end的引用是不可变的,但其date类本身是可变的,因此很容易违反这个约束条件。因此对构造器和方法的保护性拷贝是很有必要的。

public final class Period2 {
private final Date start;
private final Date end;
public Period2(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());
}
@Override
public String toString() {
return start + " -- " + end;
}
public static void main(String[] args){
Date start = new Date();
Date end = new Date();
Period2 p = new Period2(start, end);
System.out.println(p);
end.setYear(78);
p.end().setYear(78);
System.out.println(p);
}
}

从代码的输出可以看出,无论我们怎么改,时间周期p都是不可变的。

第40条: 谨慎设计方法签名

使api更易于学习和使用的设计技巧:

1.谨慎地选择方法名称。

2.不要过于追求提供便利的方法。

3.避免过长的参数列表。三种方法可以缩短过长的参数列表:

  a.把方法分解成多个方法

  b.创建辅助类

  c.从对象的构建和方法调用都采用Builder模式。

对于参数类型,要优先使用接口而不是类。

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

第41条: 慎用重载

考虑下面一个程序,它试图根据一个集合是Set还是list,还是其它集合类型,来对它进行分类:

public class CollectionClassifier {
/*public static String classify(Set<?> s){
return "Set";
}
public static String classify(List<?> s){
return "List";
}
public static String classify(Collection<?> s){
return "Unknown Collection";
} */
//避免滥用重载修正方案
public static String classify(Collection<?> s){
return s instanceof Set ? "Set" : s instanceof List ? "List" : "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));
}
}
}

如果打开注释中的三个classify方法测试,我们会发现这个程序的行为有悖常理,它打印三次“Unknown Collection”。这是因为对于重载方法的选择是静态的,而对于被覆盖的方法的选择是动态的。我们可以用上面的修正方案来实现这个功能。下面是一个覆盖的例子:

public class Overriding {

    public static void main(String[] args) {
Wine[] wines = {
new Wine(),
new SparklingWine(),
new Champagne()
};
for(Wine wine : wines){
System.out.println(wine.name());
} } }
class Wine {
String name(){
return "wine";
}
}
class SparklingWine extends Wine {
@Override
String name() {
return "sparkling wine";
}
}
class Champagne extends SparklingWine {
@Override
String name() {
return "champagne";
}
}

可以看出,代码实现了正确的行为。简而言之,“能够重载方法”并不意味着“应该重载方法”,一般情况下,对于多个具有相同参数数目的方法来说,应该尽量避免重载方法。

第42条: 慎用可变参数

具有可变参数的方法可以传入0个或者多个参数,这种方法我相信自己写的可能在少数,用得最多的可能要属反射中的getDeclaredMethod方法:

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

为什么要慎用,其中有一个原因就是很有可能在没有传入参数的时候程序没有做任何保护而导致程序错误。另外有一个原因就是它会带来一定的性能问题,EnumSet类在传入少量参数的时候是直接调用具体的方法,只有在传入大量参数时才会调用可变参数的方法,这也是它在性能方面有优势的原因,因为可变参数的每次调用都会导致进行一次数组分配和初始化。

总之,“在定义参数数目不定的方法时,可变参数是一种很方便的方式,但是它们不应该被过度滥用。如果使用不当,会产生混乱的结果”。

第43条: 返回零长度的数组或集合,而不是null

使用和避免null:null是模棱两可的,会引起令人困惑的错误,有些时候它让人很不舒服。

例如对于一个Map,调用其get(key)方法,此时若返回null,可能表示这个key所对应的值本身就是null,或者表示这个Map中没有这个key值。这是两种截然不同的语义。

书中仅是说明对于零长度的数组或者集合不应该返回null,实际上对于所有的情况,都不要轻易返回null,特别是在语义不清的情况,更别说返回null时有的客户端程序并没有处理null的这种情况。如果一定要用到null,更好的办法是单独维护它。

第44条: 为所有导出的api元素编写文档注释

现在的IDE很方便,只要轻轻敲几个快捷键就能方便的生成文档注释模板,所以不要觉得麻烦,基本的参数、返回值、用途的注释一定要写。

6.方法_EJ的更多相关文章

  1. 2.对于所有对象都通用的方法_EJ

    第8条: 覆盖equals时请遵守通用约定 我们在覆盖equals方法时,必须遵守它的通用约定: 1.自反性.对于任何非null的引用值x,x.equals(x)必须返回true: 2.对称性.对于任 ...

  2. javaSE27天复习总结

    JAVA学习总结    2 第一天    2 1:计算机概述(了解)    2 (1)计算机    2 (2)计算机硬件    2 (3)计算机软件    2 (4)软件开发(理解)    2 (5) ...

  3. mapreduce多文件输出的两方法

    mapreduce多文件输出的两方法   package duogemap;   import java.io.IOException;   import org.apache.hadoop.conf ...

  4. 【.net 深呼吸】细说CodeDom(6):方法参数

    本文老周就给大伙伴们介绍一下方法参数代码的生成. 在开始之前,先补充一下上一篇烂文的内容.在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作 ...

  5. IE6、7下html标签间存在空白符,导致渲染后占用多余空白位置的原因及解决方法

    直接上图:原因:该div包含的内容是靠后台进行print操作,输出的.如果没有输出任何内容,浏览器会默认给该空白区域添加空白符.在IE6.7下,浏览器解析渲染时,会认为空白符也是占位置的,默认其具有字 ...

  6. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  7. [C#] C# 基础回顾 - 匿名方法

    C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...

  8. ArcGIS 10.0紧凑型切片读写方法

    首先介绍一下ArcGIS10.0的缓存机制: 切片方案 切片方案包括缓存的比例级别.切片尺寸和切片原点.这些属性定义缓存边界的存在位置,在某些客户端中叠加缓存时匹配这些属性十分重要.图像格式和抗锯齿等 ...

  9. [BOT] 一种android中实现“圆角矩形”的方法

    内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...

随机推荐

  1. 剑指offer面试题25:二叉树中和为某一值的路径

    题目:输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.从根节点开始往下一直到叶节点所经过的节点形成一条路径. 解题思路:当使用前序遍历的方式访问某一节点时,把该节点添加到路径上 ...

  2. 吴恩达机器学习笔记49-主成分分析问题(Principal Component Analysis Problem Formulation)

    主成分分析(PCA)是最常见的降维算法. 在PCA 中,我们要做的是找到一个方向向量(Vector direction),当我们把所有的数据都投射到该向量上时,我们希望投射平均均方误差能尽可能地小.方 ...

  3. zabbix3.2 C/S架构搭建文档

    zabbix  是用PHP开发的.得需要搭建LAMP环境 zabbix-server 192.168.1.101zabbix-agent 192.168.1.105 zabbix 下载 https:/ ...

  4. 爬虫不过如此(python的Re 、Requests、BeautifulSoup 详细篇)

    网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本. 爬虫的本质就是一段自动抓取互联网信息的程序,从网络获取 ...

  5. 10 种保护 Spring Boot 应用的绝佳方法

    原文:developer.okta.com/blog/2018/07/30/10-ways-to-secure-spring-boot 译文:www.jdon.com/49653 Spring Boo ...

  6. .net core dump分析

    服务器上如果出现cpu内存饱满,找不到原因,那么dump文件分析必不可少. 起初是想在linux下调试.net core 的dump,但是环境一直无法安装 搞了许久没搞出来,其次文章太少了,googl ...

  7. python高级-模块(14)

    一.python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt函数,必须用语句#include <math.h>引入math.h这个头文件,否则是无法正常进行调用的. ...

  8. Spring Boot最核心的27个注解,你了解多少?

    导读 Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较火热的微服务框架Spring ...

  9. 使用 DryIoc 替换 Abp 的 DI 框架

    一.背景 你说我 Castle Windsor 库用得好好的,为啥要大费周章的替换成 DryIoc 库呢?那就是性能,DryIoc 是一款优秀而且轻量级的 DI 框架,整个项目代码就两个文件,加起来代 ...

  10. mybatis框架(4)---输入输出映射

    输入输出映射 通过parameterType制定输入参数类型 类型可以是简单类型(int String)也可以是POJO本身 或者包装类 1输入映射 关于输入简单类型和pojo本身的我就不写了,因为比 ...