编码规范
概述
编码规范(Coding Style / Code Convention)是一套约定俗成或团队统一的书写规则,用于保持代码风格一致、提高可读性和可维护性。Java 社区有 Oracle 官方约定、Google Java Style、以及国内广泛参考的《阿里巴巴 Java 开发手册》等。本文从命名、格式、注释和类与成员设计四方面归纳常用规范,便于初学者与团队协作时统一风格。
适用场景
规范用于日常编码、代码评审和新人上手;具体项目以团队或公司规范为准,本文可作为通用基础。
命名规范
命名是代码可读性的第一关。Java 对类/接口/枚举/注解、方法/变量/参数、常量、包名有通行约定。
类、接口、枚举、注解:PascalCase
使用大驼峰(每个单词首字母大写),不含下划线。
// 类
public class UserService { }
public class OrderDetailDTO { }
// 接口(可与类同名风格,或形容词/能力命名)
public interface Runnable { }
public interface Serializable { }
// 枚举
public enum OrderStatus { PENDING, PAID, SHIPPED }
// 注解
public @interface Override { }
public @interface RequestMapping { }方法、变量、参数:camelCase
使用小驼峰(首单词小写,后续单词首字母大写)。
public class ProductRepository {
private int maxPageSize = 100; // 成员变量
private String defaultCategory; // 成员变量
public List<Product> findByCategory(String categoryName) { // 方法名、参数
int page = 0; // 局部变量
return doQuery(categoryName, page);
}
}常量:UPPER_SNAKE_CASE
使用全大写,单词间用下划线分隔;通常配合 static final。
public static final int MAX_RETRY_COUNT = 3;
public static final String DEFAULT_ENCODING = "UTF-8";
private static final double PI = 3.14159;包名:全小写
包名全部小写,多个单词可连写或按域名倒序;避免使用下划线。
package com.example.project;
package com.example.user.service;注意
常量若是对象类型,其引用不可变,但对象内部仍可能被修改。真正不可变时可配合不可变类(如 String、Integer)或 Collections.unmodifiableXxx。
格式与排版
统一的缩进、大括号和行宽能显著降低阅读成本。
缩进与大括号
- 缩进:通常使用 4 个空格(或团队统一的 2/4 空格),不要混用 Tab 与空格。
- 大括号:左大括号
{不换行,与语句同一行;右大括号}单独一行。控制语句即使单行也建议写大括号,避免后续加行时出错。
// 推荐:大括号与 if 同一行,单行也写大括号
if (condition) {
doSomething();
}
for (int i = 0; i < list.size(); i++) {
process(list.get(i));
}
// 不推荐:单行省略大括号,后续加行易产生逻辑错误
if (condition) doSomething();行宽与换行
- 行宽:单行不宜过长,常见约定 80~120 字符;超长时在合适处换行(如逗号后、运算符前),缩进对齐。
- 空行:逻辑块之间、方法之间可空一行,避免一大块代码挤在一起。
// 过长时换行,下一行缩进对齐
String message = buildMessage(
userId,
orderId,
OrderStatus.PAID);注释规范
注释解释「为什么」和关键约束,而不是简单复述「是什么」。
类与公开方法
- 类:用一两句话说明类的职责、使用场景;若有过期或替代方案可注明。
- 公开方法:说明方法作用、参数含义、返回值、主要异常或前置条件。
/**
* 用户订单服务:负责订单创建、状态查询与取消。
* 所有写操作会校验用户权限。
*/
public class OrderService {
/**
* 根据订单 ID 查询订单;不存在时返回空 Optional。
*
* @param orderId 订单 ID,不能为空
* @return 订单存在时返回 Optional.of(order),否则 Optional.empty()
*/
public Optional<Order> findById(String orderId) {
// ...
}
}关键逻辑与陷阱
复杂逻辑、业务规则、或容易误解的地方应加注释;重写 equals/hashCode、实现契约的地方也应简要说明。
// 重写 equals 时必须同时重写 hashCode,否则在 HashMap 等集合中行为异常
@Override
public int hashCode() {
return Objects.hash(name, age);
}
// 使用 try-with-resources 确保流被关闭,避免资源泄漏
try (InputStream in = new FileInputStream(path)) {
return readAll(in);
}提示
同一文件内注释语言(中文/英文)保持一致;优先用团队或项目约定。
类与成员设计原则
编码规范不仅包括「怎么写名字」「怎么排版」,还包括一些设计习惯,避免常见坑。
可见性最小化
能用 private 就不用 protected,能用 protected 就不用 public;只把真正需要对外使用的成员设为 public,并通过方法而非暴露字段(封装)。
// 推荐:成员变量 private,通过方法访问
public class User {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// 不推荐:public 字段,外部可随意修改,难以维护
public class User {
public String name;
public int age;
}equals 与 hashCode 契约
重写 equals 时必须同时重写 hashCode,且参与 equals 比较的字段应参与 hashCode 计算,否则在 HashMap、HashSet 等基于哈希的集合中会出现逻辑错误。详见 常用类(Object / equals-hashCode)。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}单一职责与长度
- 类:一个类尽量只负责一类事情;类过长(如超过数百行)时考虑按职责拆分。
- 方法:方法不宜过长,逻辑复杂时拆成多个小方法,便于阅读和单元测试。
示例对比
命名与格式:推荐 vs 不推荐
// 推荐:命名清晰、常量大写、格式统一
public class OrderProcessor {
private static final int MAX_ITEMS = 100;
public void processOrder(Order order) {
if (order.getItems().size() > MAX_ITEMS) {
throw new IllegalArgumentException("订单项数量超过限制");
}
// ...
}
}// 不推荐:类名小写、常量小写、命名含糊
public class orderprocessor {
private static final int maxitems = 100;
public void ProcessOrder(Order o) {
if (o.getItems().size() > maxitems) {
throw new IllegalArgumentException("订单项数量超过限制");
}
}
}注释与封装:推荐 vs 不推荐
// 推荐:类有说明、方法有说明、成员私有
/**
* 简单内存缓存,线程不安全,仅用于单线程或已外部同步场景。
*/
public class SimpleCache<K, V> {
private final Map<K, V> map = new HashMap<>();
/** 若 key 已存在则覆盖并返回旧值,否则返回 null */
public V put(K key, V value) {
return map.put(key, value);
}
}// 不推荐:无注释、public 字段、含义不明确
public class SimpleCache<K, V> {
public Map<K, V> map = new HashMap<>(); // 暴露内部实现
public V put(K key, V value) { return map.put(key, value); } // 无说明
}注意事项
命名与类型一致
布尔类型的变量或方法命名建议使用 is、has、can 等前缀,如 isEmpty()、hasNext()、canEdit,使含义一目了然。
与 IDE 保持一致
使用 IDE 的格式化(如格式化保存、代码风格配置)并提交前统一格式化,可减少无意义的格式差异,便于 Code Review。
避免魔法数字与魔法字符串
不要把未解释的数字、字符串直接写在逻辑里;应提取为具名常量或配置,便于修改和理解。例如用 MAX_RETRY_COUNT 代替 3,用常量代替 "UTF-8"。
相关链接
- 封装与访问修饰符 — 可见性与封装
- 常用类(Object / equals-hashCode) — equals 与 hashCode 契约
- 单元测试入门 — 规范有助于写出可测代码
- Oracle Java 代码约定
- Google Java Style Guide