几乎所有大厂都会对代码规范有着严格要求,以确保多人协作开发出来的代码质量有统一的标准。在Java开发领域,《阿里巴巴Java开发手册》被国内开发者们广泛学习和应用。原手册内容较多,本文仅列出面向对象编程(OOP)方面需要注意的事项(强制遵守的规则),并说明规定背后的原因,所谓知其然,亦知其所以然。
1. 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,应该直接用类名来访问静态变量或静态方法。
2. 所有的覆写方法,必须加@Override 注解。
说明:涉及到对父类方法的覆写时,加上@Override 编译器可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名(方法名+参数类型)进行了修改,实现类也会马上编译报错。
3. 相同的参数类型,相同的业务含义,才可以使用 Java 的可变参数,避免使用 Object。
说明:J2SE 1.5中提供了Varargs机制,允许直接定义能和多个实参相匹配的形参。从而,可以用一种简单的方式,来传递数量不定的实参。可变参数必须放置在参数列表的最后。
正例:public User getUsers(String type, Integer... ids) {...}
4. 外部正在调用或者二方库依赖的接口,不允许修改方法签名(方法的名称+参数类型),避免对接口调用方的代码产生影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么。
5. 不能使用过时的方法或类。
说明:接口提供方既然明确是过时接口,就有义务同时提供新的接口;作为调用方来说,也有义务去考证过时方法的新实现是什么。
6. Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。
正例:"test".equals(object);
说明:推荐使用JDK7 引入的工具类 java.util.Objects.equals(object, "test");
7. 所有相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在 IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断。但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,如果用 == 进行判断就不会相等。
8. 所有的 POJO(Plain Ordinary Java Object)类属性必须使用包装数据类型;RPC 方法的返回值和参数必须使用包装数据类型。
说明:数据库的查询结果可能是 null,映射到POJO类的属性后,因为自动拆箱,如果属性是基本数据类型,就会有 NPE 风险。远程调用获取的对象,可能缺少某些数据,包装数据类型可以接收 null 值,可以表示额外的信息,把缺少的数据默认是0,也不合理。
9. 定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值。
说明:POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何NPE 问题,或者参数检查,都由使用者来保证。
10. 序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。
说明:注意 serialVersionUID 不一致会抛出序列化运行时异常。
11. 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。
说明:构造函数没有返回值,一旦构造函数内代码执行出了问题,外部引用是无法获知的。
12. 【强制】POJO 类必须写 toString 方法。如果继承另一个 POJO 类,注意在前面加一下 super.toString。
说明:在方法执行过程中抛出异常时,可以直接调用 POJO 类的 toString() 方法打印其属性值,便于排查问题。