高效Java(第三版) Effective Java
1. 考虑使用静态工厂方法替代构造方法 2. 当构造方法参数过多时使用builder模式 3. 使用私有构造方法或枚类实现Singleton属性 4. 使用私有构造方法执行非实例化 5. 使用依赖注入取代硬连接资源 6. 避免创建不必要的对象 7. 消除过期的对象引用 8. 避免使用Finalizer和Cleaner机制 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. 使用枚举类型替代整型常量 35. 使用实例属性替代序数 36. 使用EnumSet替代位属性 37. 使用EnumMap替代序数索引 38. 使用接口模拟可扩展的枚举 39. 注解优于命名模式 40. 始终使用Override注解 41. 使用标记接口定义类型 42. lambda表达式优于匿名类 43. 方法引用优于lambda表达式 44. 优先使用标准的函数式接口 45. 明智审慎地使用Stream 46. 优先考虑流中无副作用的函数 47. 优先使用Collection而不是Stream来作为方法的返回类型 48. 谨慎使用流并行 49. 检查参数有效性 50. 必要时进行防御性拷贝 51. 仔细设计方法签名 52. 明智而审慎地使用重载 53. 明智而审慎地使用可变参数 54. 返回空的数组或集合不要返回null 55. 明智而审慎地返回Optional 56. 为所有已公开的API元素编写文档注释 57. 最小化局部变量的作用域 58. for-each循环优于传统for循环 59. 熟悉并使用Java类库 60. 需要精确的结果时避免使用float和double类型 61. 基本类型优于装箱的基本类型 62. 当有其他更合适的类型时就不用字符串 63. 注意字符串连接的性能 64. 通过对象的接口引用对象 65. 接口优于反射 66. 明智谨慎地使用本地方法 67. 明智谨慎地进行优化 68. 遵守普遍接受的命名约定 69. 仅在发生异常的条件下使用异常 70. 对可恢复条件使用检查异常,对编程错误使用运行时异常 71. 避免不必要地使用检查异常 72. 赞成使用标准异常 73. 抛出合乎于抽象的异常 74. 文档化每个方法抛出的所有异常 75. 在详细信息中包含失败捕获信息 76. 争取保持失败原子性 77. 同步访问共享的可变数据 78. 避免过度同步 79. EXECUTORS, TASKS, STREAMS 优于线程 80. 优先使用并发实用程序替代wait和notify 81. 线程安全文档化 82. 明智谨慎地使用延迟初始化 83. 不要依赖线程调度器 84. 其他替代方式优于Java本身序列化 85. 非常谨慎地实现SERIALIZABLE接口 86. 考虑使用自定义序列化形式 87. 防御性地编写READOBJECT方法 88. 对于实例控制,枚举类型优于READRESOLVE 89. 考虑序列化代理替代序列化实例

接口仅用来定义类型

Tips
《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化。
在这里第一时间翻译成中文版。供大家学习分享之用。

22. 接口仅用来定义类型

当类实现接口时,该接口作为一种类型(type),可以用来引用类的实例。因此,一个类实现了一个接口,因此表明客户端可以如何处理类的实例。为其他目的定义接口是不合适的。

一种失败的接口就是所谓的常量接口(constant interface)。 这样的接口不包含任何方法; 它只包含静态final属性,每个输出一个常量。 使用这些常量的类实现接口,以避免需要用类名限定常量名。 这里是一个例子:

// Constant interface antipattern - do not use!
public interface PhysicalConstants {
    // Avogadro"s number (1/mol)
    static final double AVOGADROS_NUMBER   = 6.022_140_857e23;

    // Boltzmann constant (J/K)
    static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;

    // Mass of the electron (kg)
    static final double ELECTRON_MASS      = 9.109_383_56e-31;
}

常量接口模式是对接口的糟糕使用。类在内部使用一些常量,完全属于实现细节。实现一个常量接口会导致这个实现细节泄漏到类的导出API中。对类的用户来说,类实现一个常量接口是没有意义的。事实上,它甚至可能使他们感到困惑。更糟糕的是,它代表了一个承诺:如果在将来的版本中修改了类,不再需要使用常量,那么它仍然必须实现接口,以确保二进制兼容性。如果一个非final类实现了常量接口,那么它的所有子类的命名空间都会被接口中的常量所污染。

Java平台类库中有多个常量接口,如java.io.ObjectStreamConstants。 这些接口应该被视为不规范的,不应该被效仿。

如果你想导出常量,有几个合理的选择方案。 如果常量与现有的类或接口紧密相关,则应将其添加到该类或接口中。 例如,所有数字基本类型的包装类,如IntegerDouble,都会导出MIN_VALUEMAX_VALUE常量。 如果常量最好被看作枚举类型的成员,则应该使用枚举类型(条目 34)导出它们。 否则,你应该用一个不可实例化的工具类来导出常量(条目 4)。 下是前面所示的PhysicalConstants示例的工具类的版本:

// Constant utility class
package com.effectivejava.science;

public class PhysicalConstants {
  private PhysicalConstants() { }  // Prevents instantiation

  public static final double AVOGADROS_NUMBER = 6.022_140_857e23;
  public static final double BOLTZMANN_CONST  = 1.380_648_52e-23;
  public static final double ELECTRON_MASS    = 9.109_383_56e-31;
}

顺便提一下,请注意在数字文字中使用下划线字符(_)。 从Java 7开始,合法的下划线对数字字面量的值没有影响,但是如果使用得当的话可以使它们更容易阅读。 无论是固定的浮点数,如果他们包含五个或更多的连续数字,考虑将下划线添加到数字字面量中。 对于底数为10的数字,无论是整型还是浮点型的,都应该用下划线将数字分成三个数字组,表示一千的正负幂。

通常,实用工具类要求客户端使用类名来限定常量名,例如PhysicalConstants.AVOGADROS_NUMBER如果大量使用实用工具类导出的常量,则通过使用静态导入来限定具有类名的常量

// Use of static import to avoid qualifying constants
import static com.effectivejava.science.PhysicalConstants.*;

public class Test {
    double  atoms(double mols) {
        return AVOGADROS_NUMBER * mols;
    }
    ...
    // Many more uses of PhysicalConstants justify static import
}

总之,接口只能用于定义类型。 它们不应该仅用于导出常量。