第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. 项目Alpha冲刺(团队6/10)

    项目Alpha冲刺(团队6/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...

  2. python写的计算器

    import tkinter #导入tkinter模块 root = tkinter.Tk()root.minsize(280,500)root.title('xx的计算器') #1.界面布局#显示面 ...

  3. 生成uuid唯一标识符

    generate_uuid: function(){ var d = new Date().getTime(); if(window.performance && typeof win ...

  4. 从字节码看java类型转换【 深入理解 (T[]) new Object[size] 】

    我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心. 如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写 ...

  5. jsp进阶

    Jsp,前段的数据读取到后端 获取前段输入框数据 request.getParameter(前段输入框的name值) Request.代表转发,(代码在服务器内部执行的一次性请求,url地址不会发生改 ...

  6. linux下 几个常用makefile模板,亲测可用

    一 生成动态链接库的模板: ####################### # Makefile ####################### # compile and lib parameter ...

  7. 高清语音技术(WBS)及其在手机和蓝牙耳机中的实现

    高清语音也被称为宽带语音,是一种能为蜂窝网络.移动电话和无线耳机传输高清.自然语音质量的音频技术.与传统的窄带电话相比,高清语音很大程度上提高了语音质量,减少了听觉负担. 通信产业链上的所有网络和设备 ...

  8. LeetCode:1_Two_Sum | 两个元素相加等于目标元素 | Medium

    题目: Given an array of integers, find two numbers such that they add up to a specific target number. ...

  9. 避免jquery的click多次绑定方法

    $("#xxx").click(function(){}) 这样只是会在原click方法中继续添加新方法: 当然解决办法是解绑: $("#xxx").unbin ...

  10. java提高(6)---Serializable

    Serializable--初解 一 序列化是干什么的? 我们知道,在jvm中引用数据类型存在于栈中,而new创建出的对象存在于堆中.如果电脑断电那么存在于内存中的对象就会丢失.那么有没有方法将对象保 ...