Effective Java 阅读笔记——方法
38:检查参数的有效性
每当编写方法或者构造器的时候,应该考虑它的参数有哪些限制,在方法的开头处对参数进行检查,并且把这些限制写入文档。
注意:
- 对于公有方法,应该使用@throws标签在文档中说明违反参数值限制会抛出的异常
- 对于非公有的方法,通常使用断言来检查他们的参数:断言如果失败,抛出AssertionError;如果没有起到作用,本质上也不会有成本开销
private void sort(long a[]){
assert a != null;
} - 对于构造函数中的,或者参数将会被保存,后面还会用到的,尤其应该注意检查有效性
39:必要时进行保护性拷贝
如果类具有从客户端得到或者返回到客户端的可变组件,类就必须保护性的拷贝这些组件。除非拷贝成本收到限制,且类信任他的客户端不会不恰当的修改组件,就可以在文档中指明客户端的不得不恰当的修改组件,以代替保护性拷贝。
注意:
- 从客户端获取的可变组件也应该保护性拷贝,尤其在给构造函数传参时,这点平时没有注意到。而且,保护性拷贝是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是原始对象,这样可以避免检查到真正拷贝期间,数据被其他线程更改。这也很好的体现了:安全大于效率
- 对于从客户端获取的可变组件,如若其是可以被子类化的,那么就不能使用clone函数进行拷贝,因为可能传进来的是个子类对象,而clone函数可以被子类重写,从而引发安全问题。传出去的可以使用clone,因为在类的内部可以确定它是非子类的
- 真正应该注意的是:只要有可能,都应该使用不可变对象作为内部组件,以避免保护性拷贝。比如,使用Date.getTime()得到的long对象作为内部的时间组件,而不是Date,因为Date可变,而long不可变
40:谨慎的设计方法签名
设计签名方法的要点:
- 选择合理的方法名称:遵循标准习惯与含义清晰
- 避免过于追求提供便利的方法以导致方法过多,尤其对于接口。除非被经常用到的操作才考虑提供便捷方法
- 避免过长的参数列表
- 拆分方法,但应注意方法的正交性以减少方法的个数,即把方法A、B拆成a,b,c三个方法,a和c实现A,b和c实现B
- 创建辅助类用来保存参数的分组,一般为静态成员类。尤其当某些参数经常一起出现时
- 采用Builder模式:多次调用setter设置参数,然后执行方法
注意:
- 对于参数类型,若可以,优先使用接口而不是类,以避免昂贵的拷贝操作
- 对于boolean参数,优先使用两个元素的枚举类型,以使代码更易阅读和编写,且具有更好的扩展性
41:慎用重载
重载是静态的,编译时根据调用的参数决定使用重载函数的哪个版本;覆盖是动态的,运行时根据实例的实际类型决定使用哪个版本。
更加准确的说,应该避免的重载是指:参数个数相同,且不同版本的形参之间通过类型转换就可以适用不同的版本,这样就使得程序员不是很容易就确定到底调用哪个版本,从而可能导致错误。
如果需要重载,最好:
- 使不同版本具有不同的形参个数
- 如果具有相同的形参个数,那么不同版本的形参是“根本不同的类型”,让人一看就知道调用哪个,比如int和List<int>,而不是int与Integer,因为他们二者会自动拆装箱
- 如果还不行,那么应该尽量保证不同版本的重载函数对于相同的形参,所产生的行为一致
- 考虑不使用重载,而使用不同的命名,比如ObjectOutputStream有writeBoolean、writeLong、writeInt这些方法,也是一种很好的策略
42:慎用可变参数
可变参数可以接受0个或者多个指定类型的参数。可变参数机制通过先创建一个数组,数组的大小为在调用位置所传递的参数数量,然后将参数值传到数组中,最后将数组传递给方法。在定义参数数目不定的方法时,可变参数是一种很方便的方式,但不应该被滥用,以免造成混乱。造成混乱的原因可能大多出于:
- 可以传递0个参数,即不传参数
- 当参数类型定义为T时。比如如果参数定义为T... args,调用时传入的是int[],但是由于int是基本类型,而不能直接看做对象T,所以将会把int[]整体当做一个参数,而不是多个int参数
另外,当重视性能,认为可变参数的每次调用进行的数组分配和初始化可能难以满足性能要求时,可以考虑如下方式:如果对某个方法95%的调用会有三个或者更少的参数,就声明该方法的5个重载:
public void fun() {}
public void fun(int a1) {}
public void fun(int a1, int a2) {}
public void fun(int a1, int a2, int a3) {}
public void fun(int a1, int a2, int a3, int... rest) {}
43:返回零长度的数组或者集合,而不是null
这个是对于返回类型为数组或者集合的方法来说的,
好处:返回零长度的数组或者集合,就不要求客户端要有额外的代码来处理null返回值的情况。
对于返回null可能比零长度数组或集合的性能优势的反驳:
- 这样级别的性能担心是不明智的,除非确定造成了性能问题
- 因为零长度的数组或集合是不可变的,而不可变对象是有可能自由共享的,即多次调用也只会生成一个零长度的数组或集合
44:为所有导出的API元素编写文档注释
- 使用Javadoc进行注释,包括所有导出的类、接口、构造器、方法或域
- 对于方法,简洁的描述它和客户端之间的约定,说明这个方法做了什么,而不是如何完全的,以前所有的前提条件、后置条件、副作用以及线程安全性
Effective Java 阅读笔记——方法的更多相关文章
- Effective Java阅读笔记——引言
“我很希望10年前就拥有这本书.可能有人认为我不需要任何Java方面的书籍,但是我需要这本书.” ——Java之父 James Gosling 在图书馆找到这本java著作时,首先看到了这句话. ...
- Effective Java 阅读笔记——并发
66:同步访问共享的可变数据 synchronized:1互斥,阻止线程看到的对象处于不一致的状态:2保证线程在进入同步区时能看到变量的被各个线程的所有修改 Java中,除了long或者double, ...
- Effective Java 阅读笔记——枚举和注解
30:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 31:用实例域代替序数 应该给enum添加i ...
- 《Effective Java》笔记45-56:通用程序设计
将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性. 要使用局部变量的作用域最小化,最有力的方法就是在第一次使用它的地方才声明,不要过早的声明. 局部变量的作用域从它被声明的 ...
- Effective Java 学习笔记之第七条——避免使用终结(finalizer)方法
避免使用终结方法(finalizer) 终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的. 不要把finalizer当成C++中析构函数的对应物.java中,当对象不 ...
- Effective Java 读书笔记(一):使用静态工厂方法代替构造器
这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...
- Effective java读书笔记
2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...
- Effective Java读书笔记完结啦
Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...
- Effective Java要点笔记
第一章: 创建和销毁对象 类可以通过静态工厂方法来提供客户端,而不是通过构造器 优点: 自定义工厂名称,提高可读性 可以工厂里搞单例 控制实例类是哪种子类 总之是更加灵活,可读性更高 缺点: 有可能会 ...
随机推荐
- ARM Linux 3.x的设备树(Device Tree)
1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pai ...
- MyBatis知多少(12)私有数据库
如果你从事软件开发工作有了一段时间的话,那么肯定听过关于“自己动手还是花钱购买” 的争论.该争论是说,针对一个业务问题,我们是应该自己动手构建自己的解决方案呢,还是应 该花钱购买一个声称已经解决了此问 ...
- Linux高级编程--06.进程概述
进程控制块 在Linux中,每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,它通常包含如下信息: 进程id.系统中每个进程有唯一的id,在C语言中用pid_t类型表示,其实就是一个非 ...
- 正则表达式之IP地址检验
String ipRegex = "^(\\d|[1-9]\\d|1\\d*|2[0-4]\\d|25[0-5])(\\.\\1){3}$"; /* * \\d|[1-9]\\d| ...
- Android下拉刷新底部操作栏的隐藏问题
最近自己编写下拉刷新的时候,发现了一个问题,就是有一个需求是这样的:要求页面中是一个Tab切换界面,一个界面有底部操作栏,不可下拉刷新,另一个界面没有底部操作栏,但可以下拉刷新. 按照平常的做法,我在 ...
- IOS开发中设置控件内容对齐方式时容易混淆的几个属性
IOS开发中四个容易混淆的属性: 1. textAligment : 文字的水平方向的对齐方式 1> 取值 NSTextAlignmentLeft = 0, // 左对齐 NST ...
- DFS --- HNU 13307 Galaxy collision
Galaxy collision Problem's Link Mean: 给定二维坐标平面内的n个整数点,让你把这n个点划分为两个集合,同一集合内的所有点必须两两距离大于5,求这两个集合的元素个数之 ...
- Linq专题列表
什么是Linq? Linq(Language-Integrated Query),即语言集成查询.是微软的一项新技术,能够将查询功能直接引入.NET Framework3.5 所支持的编程语言(C#, ...
- IOS 之 PJSIP 笔记(一) 编译多平台支持的静态库
好久没有写博客了,这也算是我步入新工作后的第一篇技术博文吧.在进入新公司前,早就有了技术层进入下一个迭代的准备,但很多事情是意想不到的,就像我以 C# 程序员的身份面试入职的,而今却是一个全职的 IO ...
- CSS 最核心的四个概念
本文将讲述 CSS 中最核心的几个概念,包括:盒模型.position.float等.这些是 CSS 的基础,也是最常用的几个属性,它们之间看似独立却又相辅相成.为了掌握它们,有必要写出来探讨一下,如 ...