《Effective Java》读书笔记
一、引言
1.几条基本规则:(清晰性和简洁性最为重要)
模块的用户永远也不应该被模块的行为所迷惑(那样就不清晰了),模块要尽可能小,但又不能太小
代码应该被重用,而不是被拷贝
模块之间的依赖性应该尽可能的降到最小
错误应该尽早的被检测出来,最好是在编译时刻
PS.你不该盲目的遵从这些规则,但是,你应该只在偶尔的情况下,有了充分理由之后采取打破这些规则
学习编程艺术首先要学会基本的规则,然后才能知道什么时候可以打破这些规则
二、创建和销毁对象
第一条:考虑用静态工厂方法代替构造器。它有以下优势:
1)它有名称
2)不必再每次调用它的时候都创建一个新对象
3)它可以返回原类型的任何子类型的对象
4)在创建参数化类型实例的时候,它使代码变得更加简洁
缺点:
1)类如果不含共有的或者受保护的构造器,就不能被子类化(它鼓励程序复用而不是继承)
2)它与其他的静态方法实际上没有任何区别(API文档中无法明确表示出来,可以用惯用命名来弥补)
第二条:遇到多个构造器参数时要考虑用构建器。一般常用方法:
1)重叠构造器(telescoping constructor)
2) JavaBean模式
3)build构建器
PS.语法糖:NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbonydrate(27).build();
第三条:用私有构造器或者枚举类型强化Singleton属性
第四条:通过私有构造器强化不可实例化的能力
第五条:避免创建不必要的对象:
1)不要用String s = new String("xxxx");而应该用String s = "xxxxx";前者复用会创建大量实例,后者只会创建一个
2)不要使用Boolean(String);而应该用Boolwan.valueOf(String);对于同时提供了静态工厂方法和构造器的不可变类,通常用静态方法,避免创建不必要的对象
3)用long sum = 0L;而不要用Long sum = 0L;要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱
4)现代的JVM实现具有高度优化的垃圾回收器,其性能很容易就会超过轻量级对象池的性能,因此除非重量级对象(数据库连接),少用线程池。
第六条:消除过期的对象引用(主要是为了防范内存泄露):
1)栈里被弹出的元素,记得要清空引用
2)缓存用WeakHashMap来实现
3)注意监听器和其他回调,保存对象的弱引用,例如,只将他们保存成WeakHashMap
第七条:避免使用终结方法(finalizer)
原因:它不能及时执行,甚至根本就不保证它们会被执行
用处:充当安全网,或者是为了终止非关系的本地资源
用法:记得调用super.finalizer;要记得记录终结方法的非法方法;考虑使用终结方法守卫者
三、对于所有对象都通用的方法
第八条:覆盖equals时请遵守通用约定
1)自反性
2)对称性
3)传递性
4)一致性
ps.使用诀窍在P36
第九条:覆盖equals时总要覆盖hashCode
约定内容:
1) 如果两个对象相同,那么它们的hashCode值一定要相同。重写equals方法,一定要重写hashCode方法。
2) 如果两个对象的hashCode相同,它们并不一定相同,这里的对象相同指的是用eqauls方法比较。
PS.Hash算法原理:当Set接收一个元素时根据该对象的内存地址算出hashCode,看它属于哪一个区间,在这个区间里调用equeals方法。
第十条:始终要覆盖toString方法
第十一条:谨慎的覆盖clone
由于它有许多缺点,另一个实现对象拷贝的好办法是提供一个拷贝构造器或者拷贝工厂
第十二条:考虑实现Comparable接口
有些类具有内在的排序功能,但是与equals不一致。有些集合使用comparable而不是equals做同性测试。
四、类和接口
第十三条:使类的成员的可访问性最小化
封装:又被称为信息隐藏,是模块化的前提和保证
模块化的好处:
1)各个模块可以独立开发、测试、优化、使用、理解和修改
2)加快系统开发的速度,因为这些模块可以并行开发
3)减轻了维护的负担,程序员可以更快的理解模块,而且在调试的时候可以不影响其他维护的负担
4)虽然模块本身不会带来更好的性能,但是它可以帮助调节性能,通过分析知道哪些模块影响了性能
5)提高软件的可重用性,模块可以在其它系统中使用
6)模块可以降低系统风险,整个系统不可用,但是模块却有可能是可用的
第十四条:在公有类中使用访问方法而非公有域
变量应该用private定义而不是public的,只能用get/set方法取
但是如果这个类是包级私有(default)的,或者是内部类的话,则没有关系
第十五条:使可变性最小化
使类变为不可变的5条规则:
1)不要提供任何会修改对象状态的方法(也称为mutator)
2)保证类不会被扩展(使类成为final的,或者限制访问构造器)
3)使所有域都是final的
4)使所有域都是私有的
5)确保对于任何可变组件的互斥访问(如果能set则不能get对象的引用)
不可变的类(如复数类),被称作函数(functional)式的做法,相对的是过程(procedural)式的做法和命令(imperative)式的做法
不可变的类往往有一个可变配套类,来弥补它性能上的缺点(String->StringBuilder)
坚决不要为每个get方法编写一个相应的set方法,除非有很好的理由。不可变类有很多优点,唯一缺点是潜在的性能问题
第十六条:复合优先于继承:继承的功能非常强大,但是也存在诸多问题,因为它违背了封装原则。只有当子类和超类之间确实存在子类型关系时,使用继承才是恰当的。否则,可以使用复合来代替继承。
第十七条:要么为继承而设计,并提供文档说明,要么就禁止继承
第十八条:接口优于抽象类:除非演变的容易性比灵活性和功能性更为重要的时候
第十九条:接口只用于定义类型:常量接口模式是对接口的不良使用,应该使用工具类(utility class)
第二十条:类层次优于标签类:合理设计类,不要在一个类里塞太多东西,而应该使用抽象类之类的方法分层
第二十一条:用函数对象表示策略:函数指针的主要用途就是实现策略(Strategy)模式
第二十二条:优先考虑静态成员变量:四种不同的嵌套类及用法
五、泛型
第二十三条:请不要在新代码中使用原生态类型(关于List<?>,一般用于只读模式,因为不知道里面元素的类型,所以不能执行add方法,除非是null。常在方法中出现,限制方法乱add元素,出于安全性考虑。)
第二十四条:消除非受检警告:使用@SuppressWarnings("unchecked"),并添加注释,尽量加在行上而不要加在方法上。
第二十五条:列表优先于数组:优先使用泛型而不是数组来存数据,因为泛型是编译时检查类型,而数组是运行时检查,前者更安全。数组和泛型不要混合用。
第二十六条:优先考虑泛型
第二十七条:优先考虑泛型方法
第二十八条:利用有限制通配符来提升API的灵活性:PECS原则(P119)
第二十九条:优先考虑类型安全的异构容器
六、枚举和注解
第三十条:用enum代替int常量
第三十一条:用实例域代替序数
第三十二条:用EnumSet代替位域
第三十三条:用EnumMap代替序数索引
第三十四条:用接口模拟可伸缩的枚举
第三十五条:注释优于命名模式
第三十六条:坚持使用Override注解
第三十七条:用标记接口定义类型(标记注解和标记接口各有用处)
七、方法
第三十八条:检查参数的有效性
第三十九条:必要时进行保护性拷贝
第四十条:谨慎设计方法签名
第四十一条:慎用重载:重载的话,最好保证参数数目不一致,或者所有重载方法的行为一致。否则程序很容易误入重载方法。
第四十二条:慎用可变参数:3个以下的参数用重载
第四十三条:返回零长度数组或是集合,而不是null
第四十四条:为所有导出的API元素编写文档注释
八、通用程序设计
第四十五条:将局部变量的作用于最小化:
1.不要过早的声明变量,而应该在他第一次使用的地方声明
2.声明时应该初始化变量,除非是特殊情况(try块内)
3.for循环优先于while循环,因为有循环变量可以使用
4.使方法小而集中,也可以将局部变量的作用域最小化
第四十六条:for-each循环优于传统的for循环
第四十七条:了解和使用类库:程序员应该把时间花在应用程序上,而不是底层的细节上。不要重复造轮子
第四十八条:如果需要精度的答案,请避免使用float和double:应该使用BigDecimal处理小数,或者int和long处理整数
第四十九条:基本类型优先于装箱基本类型:当装箱基本类型和基本类型比较时,装箱基本类型会自动拆箱。如果null对象被自动拆箱,会报NullPointerException异常
第五十条:如果其他类型更合适,则尽量避免使用字符串:字符串经常被错误的用来代替基本类型、枚举类型和聚合类型等
第五十一条:当心字符串连接的性能
第五十二条:通过接口引用对象:优先使用接口,这样会更灵活更聪明
第五十三条:接口优于反射机制:应该仅仅使用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类
第五十四条:谨慎的使用本地方法
第五十五条:谨慎的进行优化:不要费力去编写快速的程序——应该努力编写好的程序,速度自然会随之而来
第五十六条:遵守普遍接受的命名惯例
九、异常
第五十七条:只针对异常的情况才使用异常:逻辑控制中,应该使用“状态测试方法”或“可识别的返回值”方法,而不是把异常用于控制流
第五十八条:对可恢复的情况使用受检异常,对编程错误使用运行时异常
第五十九条:避免不必要的使用受检的异常
第六十条:优先使用标准的异常
第六十一条:抛出与抽象对应的异常
第六十二条:每个方法抛出的异常都要有文档
第六十三条:在细节消息中包含能捕获失败的信息
第六十四条:努力使失败保持原子性
第六十五条:不要忽略异常
十、并发
第六十六条:同步访问共享的可变数据
第六十七条:避免过度同步
第六十八条:excutor和task优先于线程
第六十九条:并发工具优先于wait和notify
第七十条:线程安全性的文档化
第七十一条:慎用延迟初始化
第七十二条:不要依赖线程调度器:确保可运行线程的平均数量不明显的多于处理器的数量
第七十三条:避免使用线程组(thread group),已基本废弃,应该使用线程池executor
十一、序列化
第七十四条:谨慎的实现Serializable接口
第七十五条:考虑使用自定义的序列化形式
第七十六条:保护性的编写readObject方法
第七十七条:对于实例控制,枚举类型优先于readResolve
第七十八条:考虑用序列化代理代替序列化实例
《Effective Java》读书笔记的更多相关文章
- csapp读书笔记-并发编程
这是基础,理解不能有偏差 如果线程/进程的逻辑控制流在时间上重叠,那么就是并发的.我们可以将并发看成是一种os内核用来运行多个应用程序的实例,但是并发不仅在内核,在应用程序中的角色也很重要. 在应用级 ...
- CSAPP 读书笔记 - 2.31练习题
根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1) 属于第一种情况 sum = x ...
- CSAPP读书笔记--第八章 异常控制流
第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...
- CSAPP 并发编程读书笔记
CSAPP 并发编程笔记 并发和并行 并发:Concurrency,只要时间上重叠就算并发,可以是单处理器交替处理 并行:Parallel,属于并发的一种特殊情况(真子集),多核/多 CPU 同时处理 ...
- 读书笔记汇总 - SQL必知必会(第4版)
本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...
- 读书笔记--SQL必知必会18--视图
读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...
- 《C#本质论》读书笔记(18)多线程处理
.NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...
- C#温故知新:《C#图解教程》读书笔记系列
一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...
- C#刨根究底:《你必须知道的.NET》读书笔记系列
一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...
- Web高级征程:《大型网站技术架构》读书笔记系列
一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...
随机推荐
- #define和预编译指令
今天再总结一点#define和预处理指令的使用. 预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器.可见预处理过程先于编译器对源代码进行处理. 预处理指令是以#开头的代码行,#后是 ...
- Javascript中那些偏门的知识
1.(functiong(){})() 和 (function(){}())有细微差别,()是强制运算符,第一种写法强制返回函数本身,然后调用:第二种写法是强制返回函数执行的结果. 2.json格式 ...
- com.code.servlet
package com.code.servlet; import java.io.IOException; import java.util.LinkedHashMap; import java.ut ...
- javascript笔记07:使用Object类为实例定义方法和属性
function Person() {} Person.prototype = { nickName:"john", , showInfo:function() { return ...
- Android_Gallery
xml布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:to ...
- UVa 1645 Count(**)
题目大意:输入n,统计有多少个n个结点的有根树,使得每个深度中所有结点的子结点数相同.结果模1000000007. 思路:根据题意,每个结点的每个子树都是相同的.所以n结果为n-1的所有约数的结果加起 ...
- Mysql数据库的索引原理
写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将 ...
- Java编写的文本编辑器(菜鸟作品)
//这是主窗体文件 Wordwin.java import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.sw ...
- 重大发现Android studio 如何简单快速修改package name
好多人都发现Android studio修改包名比较麻烦,只能一级一级的修改,今天偶尔发现了一个快捷方法. 废话不多说: 1 打开项目的AndroidManifest.xml文件 2 鼠标光笔定位到你 ...
- 使用EF访问数据库,出现“System.Data.Entity.Internal.AppConfig”的类型初始值设定项引发异常。
今天在使用的EF时候,发生了"System.Data.Entity.Internal.AppConfig"的类型初始值设定项引发异常.这样的一个错误 查了原因,原来是appconf ...