一、面向对象

1、构造器参数太多

如果参数很多,会导致构造方法非常多,拓展性差,代码难编写,且难以看懂。 用 JavaBeans 模式,get 和 set 一行构造编程多行代码实现,需要使用额外机制确保一致性和线程安全。
用 builder 模式:1、5 个或者 5 个以上的成员变量 2、参数不多,但是在未来,参数会增加。

2、不需要实例化的类应该构造器私有

如,一些工具类提供的都是静态方法,这些类是不应该提供具体的实例的。可以参考 JDK 中的 Arrays。
好处:防止使用者 new 出多个实例。

3、不要创建不必要的对象

4、避免使用终结方法

finalizer 方法,jdk 不能保证何时执行,也不能保证一定会执行。如果有确实要释放的资源应该用 try/finally。

5、使类和成员的可访问性最小

模块对外部其他模块来说,隐藏其内部数据和其他实现细节——封装 编写程序和设计架构,最重要的目标之一就是模块之间的解耦。使类和成员的可访问性最小化无疑是有效的途径之一。 类似于微服务。

6、使可变性最小化

尽量使类不可变,不可变的类比可变的类更加易于设计、实现和使用,而且更不容易出错,更安全。 常用的手段:
不提供任何可以修改对象状态的方法;
使所有的域都是 final 的。
使所有的域都是私有的。
使用写时复制机制。

7、复合优先于继承

继承容易破坏封装性,而且会使子类的实现依赖于父类。
复合则是在类中增加一个私有域,引用类的一个实例,这样的话就避免了依赖类的具体实现。
例如在hashset中继承它,实现一个count方法,在add、addAll时对count进行增加操作,会出现问题。

8、接口优于抽象类

接口只有方法申明,抽象类可以写方法的实现。
java 是个单继承的(不能继承多个抽象类),但是类允许实现多个接口。 所以当发生业务变化时,新增接口,实现接口只需要新曾接口即可。但是抽象类有可能导致不需要变化的类也不得不实现新增的业务方法。
JDK 源码中常用的一种设计方法:定义一个接口,声明一个抽象的骨架类实现接口,骨架类类实现通用的方法,而实际的业务类可以同时实现接口又继承 骨架类,也可以只实现接口。
如 HashSet 实现了 implements Set 接口 但是又 extends 类 AbstractSet,而 AbstractSet 本身也实现了 Set 接口。其他如 Map,List 都是这样的设计的。

二、方法

1、可变参数谨慎使用

可变参数是允许传 0 个参数的
如果是参数个数在 1~多个之间的时候,要做单独的业务控制。 具体代码不优雅。

2、返回零长度的数组或集合,不要返回 null

方法的结果返回 null,会导致调用方的要单独处理为 null 的情况。返回零长度,调用方可以统一处理,如使用 foreach 即可。
JDK 中也为我们提供了 Collections.EMPTY_LIST 这样的零长度集合

三、通用程序设计

1、用枚举代替常量

声明的一个枚举本质就是一个类,每个具体的枚举值就是这个枚举类的实例。

  1. 使用常量容易在写代码时写错
  2. 使用常量如果要使用描述时比较麻烦
  3. 其他类使用常量时,类编译时会把常量值直接写到字节码中,如果常量值有变化,所有相关的类需要重新编译,否则会不可预料的错误
  4. 枚举还可和行为绑定

2、将局部变量的作用域最小化

  1. 在第一次使用的地方进行声明
  2. 局部变量都是要自行初始化,初始化条件不满足,就不要声明 最小化的好处,减小局部变量表的大小,提高性能;同时避免局部变量过早声明导致不正确的使用。

3、精确计算,避免使用 float 和 double

float 和 double 在 JVM 存储的时候,有部分要做整数位,有部分要做小数位,所以存在精度上的问题,可以使用 int 或者 long 以及 BigDecimal

4、当心字符串连接的性能

在存在大量字符串拼接或者大型字符串拼接的时候,尽量使用 StringBuilder 和 StringBuffer

5、控制方法的大小

方法过大不宜与维护