花了近半年的时间,才把《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 |
|
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记录 |