Effective Java
2021-07-26 08:27:36 3 举报
AI智能生成
Effective Java
作者其他创作
大纲/内容
创建和销毁对象
1. 静态工厂方法代替Constructor
2. Builder代替多参数Constructor
3. 私有Constructor 或Enum 强化单例
4. 私有Constructor 强化不可实例
5. 优先依赖注入引用资源
6. 避免创建不必要的对象
7. 消除过期对象引用
8. 避免使用终结方法和清除方法
9. try-with-resource 优先于 try-catch
Object 的通用方法
10. 覆盖equals() 遵守通用约定
11. 覆盖equals() 时覆盖hashCode()
12. 始终覆盖toString()
13. 谨慎地覆盖clone()
14. 考虑实现Comparable 接口
类和接口
15. 使类和成员的可访问性最小
16. 在公有类而非公有域中使用访问方法
17. 使可变性最小化
定义
不可变类简单来说是它的实例不能被修改的类
五条规则
不要提供修改对象状态的方法
确保这个类不能被继承
把所有属性设置为 final
把所有的属性设置为 private
确保对任何可变组件的互斥访问
在构造方法,访问方法和 readObject 方法(条目 88)中进行防御性拷贝(条目 50)
18. 复合优先于继承
19. 设计继承并提供文档 OR 禁止继承
20. 接口优于抽象类
接口VS抽象类
抽象类定义的类型,类必须是抽象类的子类
Java 只允许单一继承,限制严格
接口是定义混合类型(mixin)的理想选择
Java8 中引入了接口的默认方法(default methods )
21. 为后代设计接口
Java 8 添加了默认方法(default method)
但是非常仔细地设计接口仍然是非常重要
问题
子类采用默认方法实现Bug
22. 接口只用于定义类型
常量接口模式是对接口的糟糕使用
23. 类层次优于标签类
包含一个标签属性(tag field),表示实例的风格
24. 静态成员类优于非静态成员类
嵌套类(nested class)是在另一个类中定义的类
嵌套类应该只存在于其宿主类(enclosing class)中
如果一个嵌套类在其他一些情况下是有用的,那么它应该是一个顶级类
四种嵌套类
静态成员类
非静态成员类
匿名类
局部类
25. 限制源文件为单个顶级类
泛型
26. 不要使用 raw type
如果你使用原始类型,则会丧失泛型的所有安全性和表达上的优势
例外
类字面值(class literals)
instanceof 操作符
27. 消除unchecked 的警告
28. List 优于 Array
29. 优先考虑泛型
30. 优先考虑泛型方法
31. 利用有限通配符提升API 的灵活性
32. 谨慎使用泛型和可变参数
33. 优先考虑类型安全的异构容器
枚举和注解
34. 用enum 代替 int 常量
35. 用实例域代替序数
36. 用EnumSet 代替位域
37. 用EnumMap 代替序数索引
38. 用接口模拟可扩展的enum
39. 注解优先于命名模式
40. 坚持使用Override 注解
41. 用标记接口定义类型
Lambda 和 Stream
42. Lambda 优于匿名类
43. 方法引用优于Lambda
44. 坚持使用标准的函数接口
45. 谨慎使用Stream
46. 优先选择Stream 中无副作用的函数
Comparator
comparing
compare
thenComparing
...
BinaryOperator
minBy
maxBy
Collectors
toList
toMap
toConcurrentMap
groupingBy
groupingByConcurrent
counting
minBy
maxBy
子主题
47. Stream 要优先用Collection 作为返回类型
48. 谨慎使用 Stream并行
方法
49. 检查参数的有效性
50. 必要时进行保护性copy
51. 谨慎设计方法签名
52. 慎用重载
53. 慎用可变参数
54. 返回空集合,而不是null
55. 谨慎返回Optional
56. 为所有导出的API 元素编写文档注释
通用编程
57. 将局部变量的作用域最小化
优先选择 for 循环而不是 while 循环
58. for-each 循环优先于传统的for 循环
不能使用场景
有损过滤(Destructive filtering)
如果需要遍历集合,并删除指定选元素,则需要使用显式迭代器,以便可以调用其 remove 方法
Java8 的Collection.removeIf
转换
如果需要遍历一个列表或数组并替换其元素的部分或全部值,那么需要列表迭代器或数组索引来替换元素的值
并行迭代
如果需要并行地遍历多个集合,那么需要显式地控制迭代器或索引变量,以便所有迭代器或索引变量都可以同步进行
59. 了解和使用类库
60. 如果需要精确,避免使用float 和double
61. 基本类型优先于装箱基本类型
62. 如果其他类型更合适,则尽量避免使用字符串
63. 了解字符串连接的性能
64. 通过接口引用对象
65. 接口优先于反射机制
66. 谨慎地使用Native 方法
67. 谨慎地进行优化
68. 遵守普遍接受的命名惯例
异常
69. 只针对异常的情况才使用异常
异常应该只用于异常的情况下;他们永远不应该用于正常的程序控制流程
异常的模式比标准模式要慢得多
70. 对可恢复的情况使用checked 异常,对编程错误则RuntimeException
受检异常
如果期望调用者能够合理的恢复程序运行
用运行时异常
表明编程错误
所有非受检的 throwable 都应该是 RuntimeExceptiond 子类
71. 避免不必要地使用checked 异常
72. 优先使用标准的异常
73. 抛出与抽象对应的异常
74. 每个方法抛出的所有异常都要建立文档
75. 在细节消息中包含失败-捕获信息
76. 保持失败保持原子性
失败的方法调用应该使对象保持在被调用之前的状态
77. 不要忽略异常
如果选择忽略异常, catch 块中应该包含一条注释,说明为什么可以这么做
并发
78. 同步访问共享的可变数据
79. 避免过度同步
80. executor、task 和 stream 优先于线程
81. 并发工具优先于wait 和notify
82. 线程安全性的文档化
83. 慎用延迟初始化
84. 不要依赖于线程调度器
序列化
85. 其他方法优先于Java 序列化
86. 谨慎地实现Serializable 接口
87. 考虑使用自定义的序列化形式
88. 保护性地编写readObject 方法
89. 对于实例控制,enum 优先于readResolve
90. 考虑用序列化代理代替序列化实例
0 条评论
下一页