6.方法_EJ
第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的更多相关文章
- 2.对于所有对象都通用的方法_EJ
第8条: 覆盖equals时请遵守通用约定 我们在覆盖equals方法时,必须遵守它的通用约定: 1.自反性.对于任何非null的引用值x,x.equals(x)必须返回true: 2.对称性.对于任 ...
- javaSE27天复习总结
JAVA学习总结 2 第一天 2 1:计算机概述(了解) 2 (1)计算机 2 (2)计算机硬件 2 (3)计算机软件 2 (4)软件开发(理解) 2 (5) ...
- mapreduce多文件输出的两方法
mapreduce多文件输出的两方法 package duogemap; import java.io.IOException; import org.apache.hadoop.conf ...
- 【.net 深呼吸】细说CodeDom(6):方法参数
本文老周就给大伙伴们介绍一下方法参数代码的生成. 在开始之前,先补充一下上一篇烂文的内容.在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作 ...
- IE6、7下html标签间存在空白符,导致渲染后占用多余空白位置的原因及解决方法
直接上图:原因:该div包含的内容是靠后台进行print操作,输出的.如果没有输出任何内容,浏览器会默认给该空白区域添加空白符.在IE6.7下,浏览器解析渲染时,会认为空白符也是占位置的,默认其具有字 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- [C#] C# 基础回顾 - 匿名方法
C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...
- ArcGIS 10.0紧凑型切片读写方法
首先介绍一下ArcGIS10.0的缓存机制: 切片方案 切片方案包括缓存的比例级别.切片尺寸和切片原点.这些属性定义缓存边界的存在位置,在某些客户端中叠加缓存时匹配这些属性十分重要.图像格式和抗锯齿等 ...
- [BOT] 一种android中实现“圆角矩形”的方法
内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...
随机推荐
- kafka学习笔记——基本概念与安装
Kafka是一个开源的,轻量级的.分布式的.具有复制备份.基于zooKeeper协调管理的分布式消息系统. 它具备以下三个特性: 能够发布订阅流数据: 存储流数据时,提供相应的容错机制 当流数据到达时 ...
- Pool:小对象缓存or复用
对象复用 使用链表作为pool来保存要复用的对象. pool字段 obtain recycle 案例1 android.os.Message private static Message sPool; ...
- 工作jQuery基础复习(一)
1.prop() 方法 设置或者返回被选元素的属性和值 当该方法用于返回属性值时,则返回第一个匹配元素的值 当该方法设定属性值时,则为匹配元素集合设置一个或者多个属性/值对
- 使用HOG特征+BP神经网络进行车标识别
先挖个坑,快期末考试了,有空填上w 好了,今晚刚好有点闲,就把坑填上吧. //-------------------------------开篇---------------------------- ...
- JVM内存分配和垃圾收集策略
java内存区域 程序计数器 因为java可以多线程并发执行,因此,为了线程切换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器.记录正在执行的虚拟机字节码指令的地址. 这个区域不会产生内 ...
- 微信小程序支付接入实战
1. 微信小程序支付接入实战 1.1. 需求 最近接到一个小程序微信支付的需求,需要我写后台支持,本着能不自己写就不自己写的cv原则,在网上找到了些第三方程序,经过尝试后,最后决定了这不要脸作者的 ...
- JSTL 和 EL
EL表达式 Expression Language 语法${作用域中的值} 使用EL表达式时,需要在page标签中写上isELIgnored="false",否则EL表达式不生 ...
- hbaes之createTable执行流程
hbase的客户端代码并不想hive一样用java编写,shell调用,而是使用ruby编写. 在admin.rb文件中方法create,其中接受两个参数,其中第二个参数类型为变长参数. 而在crea ...
- 用python自制微信机器人,定时发送天气预报
0 引言 前段时间找到了一个免费的天气预报API,费了好段时间把这个API解析并组装成自己想用的格式了,就想着如何实现每天发送天气信息给自己.最近无意中发现了wxpy库,用它来做再合适不过了.以下是w ...
- Docker学习之1—基础及安装
Docker介绍: Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制 ...