Effective Java

创建和销毁对象

  • 1. 用静态工厂方法代替构造器
  • 2. 遇到多个构造器参数时考虑构建器
  • 3. 用私有构造器或者枚举类型强化单例
  • 4. 通过私有构造器强化不可实例化的能力
  • 5. 优先考虑依赖注入来引用资源
  • 6. 避免创建不必要的对象
  • 7. 消除过期的对象引用
  • 8. 避免使用终结方法和清除方法
  • 9. try-with-resources优于try-finally

对于所有对象都通用的方法

  • 10. 覆盖equals时遵循通用约定
  • 11. 覆盖equals时总是覆盖hashCode
  • 12. 始终要覆盖toString
  • 13. 谨慎地覆盖clone
  • 14. 考虑实现Comparable接口

类和接口

  • 15. 使类和成员的可访问性最小
  • 16. 在公有类中使用访问方法而非公有域
  • 17. 使可变性最小化
  • 18. 组合优于继承
  • 19. 要么设计继承并提供文档说明,要么禁止继承
  • 20. 接口优于抽象类
  • 21. 为后代设计接口
  • 22. 接口只用于定义类型
  • 23. 类层次优于标签类
  • 24. 静态成员类优于非静态成员类
  • 25. 限制源文件为单个顶级类

泛型

  • 26. 不要使用原始类型
  • 27. 消除非首检警告
  • 28. 列表优于数组
  • 29. 优先考虑泛型
  • 30. 优先考虑泛型方法
  • 31. 利用有限制通配符来提升API灵活性
  • 32. 谨慎并用泛型和可变参数
  • 33. 优先考虑类型安全的异构容器

枚举和注解

  • 34. 用enum代替int常量
  • 35. 用实例域代替序数
  • 36. 用EnumSet代替位域
  • 37. 用EnumMap代替序数索引
  • 38. 用接口模拟可扩展的枚举
  • 39. 注解优先于命名模式
  • 40. 坚持使用@Override注解
  • 41. 用标记接口定义类型

Lambda和Stream

  • 42. Lambda优于匿名类
  • 43. 方法引用优于Lambda
  • 44. 坚持使用标准的函数接口
  • 45. 谨慎地使用Stream
  • 46. 优先选择Stream中无副作用的函数
  • 47. Stream要优先用Collection作为返回类型
  • 48. 谨慎使用Stream并行

方法

  • 49. 检查参数的有效性
  • 50. 必要时进行保护性拷贝
  • 51. 谨慎设计方法签名
  • 52. 慎用重载
  • 53. 慎用可变参数
  • 54. 返回零长度的数组或者集合,而不是null
  • 55. 谨慎返回Optional
  • 56. 为所有导出的API元素编写文档注释

通用编程

  • 57. 将局部变量的作用域最小化
  • 58. for-each循环优于传统的for循环
  • 59. 了解和使用类库
  • 60. 如果需要精准答案,避免使用float或double
  • 61. 基本类型优于包装类
  • 62. 如果其它类型更合适,避免使用字符串
  • 63. 了解字符串连接的性能
  • 64. 通过接口引用对象
  • 65. 接口优先与反射机制
  • 66. 谨慎地使用本地方法
  • 67. 谨慎地使用优化
  • 68. 遵守普遍接收的命名惯例

异常

  • 69. 只针对异常的情况才使用异常
  • 70. 对可恢复的情况使用受检异常,对编程错误使用运行时异常
  • 71. 避免不必要地使用受检异常
  • 72. 优先使用标准的异常
  • 73. 抛出与抽象对应的异常
  • 74. 每个方法抛出的异常都要建立文档
  • 75. 在细节消息中包含失败-捕获信息
  • 76. 努力使失败保持原子性
  • 77. 不要忽略异常

并发

  • 78. 同步访问共享的可变数据
  • 79. 避免过度同步
  • 80. executor、task、stream优于线程
  • 81. 并发工具优于wait和notify
  • 82. 线程安全性的文档化
  • 83. 慎用延迟初始化
  • 84. 不要依赖于线程调度器

序列化

  • 85. 其它方法优先与Java序列化
  • 86. 谨慎地实现Serializable接口
  • 87. 考虑使用自定义的序列化形式
  • 88. 保护性地编写readObject方法
  • 89. 对于实例控制,枚举类型优先于readResolve
  • 90. 考虑用序列化代理代替序列化实例