effective-java[第三版]

花了近半年的时间,才把《effective-java[第三版]》基本阅读完,由于自己JAVA基础差,很多地方不理解,暂时把阅读中的理解做个记录,后续再完善。

effective-java

effective-java[第三版]书中的代码示例,JDK版本为1.8.0_181

作者提供的本书代码示例

https://github.com/jbloch/effective-java-3e-source-code.git

目录结构

chapter item explanation
02 创建和销毁对象
02 实体类多个参数的情况下,推荐使用构建器Build
03 Singleton单例的多种实现方式:饥饿方式、懒加载方式、枚举方式、静态内部类方式(饥饿+懒加载的融合)
05 推荐依赖注入的方式来引入资源,有诸多好处
06 避免创建不必要的对象,但是要看是什么类型的对象,创建新的还是复用已有的是要比较各方面代价后的一个结果
07 及时将过期的引用置为null,但并不是每个对象都要手动清除引用,大部分还是交给GC来做,文中主要说明了内存泄漏的3个主要来源
09 针对需手工关闭的资源,JDK1.7之后有了一种新的写法,不用再手动close资源了
03 所有对象都通用的方法
10 equals方法的原则和写法,推荐使用lombok或者AutoValue来自动生成
11 hashCode方法的重写应该是和equals方法一起的,推荐使用lombok或者AutoValue来自动生成
13 clone方法尽量不要重写,建议使用拷贝构造器或拷贝工厂方法来替代,写clone方法时务必注意引用类型域的层级clone
14 如果类的对象要是有序的,提供3种方式来实现排序逻辑
04 类和接口编写时的注意事项
15 使类和成员的可访问性最小化:private-default-protected-public
16 公有类的域不应该直接暴露数据域的访问,而是应该提高相应域的操作方法,比如:域设置为private,然后提供get/set方法
17 使类和成员的可变性最小化:final修饰
18 复合优先于继承,因为继承是打破了封装性的,让程序变的脆弱
19 必要时如何编写可继承类:①专门为了继承而设计的②提供很好的说明文档(相当于永久承诺)
20 接口优于抽象类:①接口有多种好处②对接口提供一个抽象的骨架实现类,可以结合接口和抽象类的优点
21 为后代设计接口时,需要考虑的地方
22 接口只用于定义类型,不应该用于定义和导出常量,同时提供了几种定义常量的方案
23 标签类很少适用,尽量拆分成类层次的方式
24 4种嵌套类的声明方式及常见的适用场景
25 一个java文件不要定义多个顶级类,这个在IDEA下不存在,会校验出来的
05 泛型的使用
26 避免使用原生态类型,因为它不是类型安全的,运行时会有异常
27 通过注解@SuppressWarnings(“unchecked”)消除非受检的警告,前提是你确保它是类型安全的
28 泛型数组在使用时如果出现编译错误或警告,优先考虑用泛型列表替换数组
29 泛型类的编写及注意规范
30 泛型方法的编写及注意规范
31 API定义时,考虑使用通配符来提高灵活性,并明白什么场景下使用通配符及如何使用
32 泛型和可变参数是不合的,并用泛型和可变参数的注意事项以及替代方案
33 如何编写类型安全的异构容器,主要是通过类型令牌
06 枚举和注解的使用
34 当需要定义一组固定常量时,enum比int常量有更多的好处:可读性、安全性等
35 尽量不使用enum自带的序数值ordinal,而是给枚举添加一个域来记录
36 用EnumSet代替位域,但是平常也没啥场景要使用位域
37 当根据Enum来进行分类的时候,不要使用enum[]或list并且用enum的序数ordinal来作为索引,而是应该使用EnumMap
38 因为枚举无法继承扩展,所以这里作者建议同一类的enum都implement同一个接口来模拟枚举的扩展
39 通过编写一个@Test注解,来说明注解的写法和用法
40 覆盖方法记得使用@Override注解
41 论述标记接口和标记注解的优缺点,及使用的场景
07 Lambda和Stream的使用
42 Lambda、方法引用都是匿名类的一个升级方案,都是为了提供函数对象的,最终的目的是函数编程
43 提供函数对象:方法引用>Lambda>匿名类
44 使用函数接口时,优先使用java.util.function下预定义的,本章对下面的接口做了一个分类说明,方便记忆
45 Stream的写法,以及和迭代写法的对比和选用场景
46 实在看不懂,后续专题研究
47 实在看不懂,后续专题研究
48 实在看不懂,后续专题研究
08 方法-编写方法时的注意事项和技巧
49 方法参数的有效性检查(何时需要检查?如何检查?检查出不合法参数如何处理?)
50 参数的保护性拷贝(为何:防止客户端参数搞破坏?如何拷贝?拷贝是有成本的,所以对于受信任的客户端不用保护性拷贝)
51 设计方法的签名的注意事项:方法名+参数列表
52 不建议使用重载,因为有容易混淆等问题,最好使用更加形象而不同的方法名来进行区分
53 可变参数实际上是一个数组,存在一些问题(运行时而不是编译时发生失败,存在数组的分配和初始化影响性能),需谨慎使用
54 当方法返回值是数组或集合时,不要返回null,而是返回空集合或数组
55 使用optional作为返回值,optional理解就是一种特殊集合,将真正的回参放入其中,显性的要求方法调用方进行回参的校验,不过用的时候需要做好评估,毕竟是又包装了一层,存在性能影响
56 给接口、类、方法、字段添加规范的注释,通过javadoc生成API文档
09 日常编码时的注意事项
57 局部变量的作用域最小化,在用的时候再进行声明,而不是像C语言一样声明一大堆
58 for-each>传统for循环>while循环,主要是从简介性、灵活性、出错预防方面来考虑
59 使用现成的JAVA类库或第三方类库,避免重复造轮子
60 精确的金额计算,避免使用float或double,而是BigDecimal或int或long
61 能使用基本类型的时候就不要使用装箱基本类型,避免不必要的装箱-拆箱
62 应该用基本类型或者枚举类型的时候,避免使用字符串
63 字符串连接时,使用StringBuilder而不是String
64 通过接口或者最小的具体类来引用对象,算是多态的一种具体使用
65 反射一般多用于Spring、Mybatis等框架中,日常代码中使用,应该仅仅使用反射来实例化对象,而对象的引用则使用接口或者超类
66 使用本地方法前三思,因为常用的native方法,JAVA API基本上都进行了封装
67 进行优化前,一定要有详细的优化方案和评估
68 养成良好的命名规范
10 异常的编码规范
69 尽量是在方法不正常的时候再使用异常,而不是把异常当成一种控制流使用,一般情况下,咱们编码不存在这样的问题
70 两种异常的使用场景:受检异常(方法声明时就抛出的异常,这种是期望调用方能够适当的恢复时采用这种异常,比如流关闭异常)、运行时异常(方法不明确声明,用来表明时调用方编程错误,才导致的异常,比如传入的参数不符合约定)
71 受检异常虽然可以强迫调用方处理异常,提高代码可靠,但是也导致API使用不变代码冗余等问题,符合一下2个条件可考虑使用受检异常:1.正确使用API并不能阻止异常的发生2.发生异常时API调用方可以立即采取有用的动作处理
72 如果没有正当的理由,不要自己编写异常类,JAVA定义的常用标准异常足够用了
73 当低层异常对于高层有用时,再使用异常转译向上抛出,不然最好就在低层进行异常处理就行了
74 通过@throws标签为异常建立文档,说明什么情况下会抛出什么样的异常
75 编写异常类时,为了记录和排查,一定要将异常的细节信息包含在异常类中
76 让一个方法保持异常失败原子性(异常发生后不影响对象的可用状态)的几种方法处理方式
78 不要忽略异常,如果你catch住的异常无需处理,起码也在catch代码块里进行注释说明或者LOG记录