Skip to content

代码规范约定

本教程有非常严格的代码规范。这份规范有两个目的:

  1. 让你看得舒服 — 全文统一风格,降低阅读负担
  2. 让你直接用 — 这些规范都是从阿里 Java 开发手册 + Google Java Style + 各大厂实践综合而来,企业项目直接照搬

命名规范

类型规则示例
类名UpperCamelCase(首字母大写)UserControllerOrderService
方法名lowerCamelCase(首字母小写)getUserByIdcalculateTotal
变量名lowerCamelCaseuserNameorderList
常量名UPPER_SNAKE_CASEMAX_RETRY_COUNTDEFAULT_TIMEOUT
包名全小写,名词com.example.usercom.taskflow.rbac
接口名名词或形容词(不加 I 前缀)UserServiceComparable
枚举名UpperCamelCaseOrderStatus
枚举值UPPER_SNAKE_CASEPENDINGPAIDSHIPPED

❌ 反例(新手常见错误)

java
// ❌ 全用拼音首字母
public class Yhqx {                        // 应为 UserController
    public void chaxun() { }               // 应为 query
    public String xm;                      // 应为 userName
}

// ❌ 缩写不一致
public String getUsrName();                // 一会儿 User 一会儿 Usr
public String getUserID();                 // ID 应为 Id

// ❌ 复数形式混乱
private List<User> userList;               // 下个方法用 users
private List<User> users;                  // 应统一为 userList 或 userItems

✅ 正例(企业级标准)

java
/**
 * 用户控制器
 *
 * @author taskflow
 * @since 1.0.0
 */
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {              // ① 类名 UpperCamelCase

    private final UserService userService; // ② 依赖注入用 final + 构造器

    @GetMapping("/{id}")
    public Result<UserVO> getUserById(     // ③ 方法名 lowerCamelCase
        @PathVariable @Min(1) Long id      // ④ 参数用包装类,便于校验 null
    ) {
        UserDO user = userService.getById(id);
        return Result.success(UserConverter.toVO(user));
    }

    private static final int MAX_PAGE_SIZE = 100;  // ⑤ 常量 UPPER_SNAKE_CASE
}

注释规范

本教程代码注释有三种层次:

1. 行内 // 数字 注释:解释设计意图

java
public class OrderService {
    private static final int MAX_RETRY = 3;  // ① 重试上限:3 次是支付场景的业界经验值

    public void pay(Order order) {
        // ② 先扣库存再支付,避免超卖(高一致性需求)
        inventoryService.deduct(order);
        try {
            paymentService.charge(order);
        } catch (PaymentException e) {
            // ③ 支付失败必须回滚库存,否则用户付不了钱但库存没了
            inventoryService.restore(order);
            throw e;
        }
    }
}

2. Javadoc:/** */:解释对外契约

java
/**
 * 根据用户 ID 查询用户信息
 *
 * @param id 用户 ID(必须 > 0)
 * @return 用户视图对象;用户不存在时返回 null
 * @throws IllegalArgumentException 当 id <= 0 时抛出
 * @since 1.0.0
 */
public UserVO getUserById(Long id);

3. 「为什么这样写」卡片:解释架构决策

markdown
::: tip 为什么用构造器注入而不是 @Autowired 字段注入?
字段注入的三个问题:
1. 无法注入 final 字段,变量可被外部修改
2. 无法在没有 Spring 容器的单元测试中手动构造对象
3. 隐藏了类的依赖关系,不看代码无法知道这个类需要什么

构造器注入的三个好处:
1. final 字段保证不可变,线程安全
2. 测试时可以 `new UserService(mockUserDao, mockLogger)`
3. 类的依赖在构造器签名上一目了然

这是 Spring 官方推荐的方式(Spring 4.3+ 单构造器可省略 @Autowired)。
:::

代码格式规范

缩进与空格

java
// ✅ 4 空格缩进(不用 Tab)
public void method() {
    if (condition) {
        doSomething();
    }
}

// ✅ 操作符前后加空格
int sum = a + b * c;

// ✅ 关键字后加空格
if (x > 0) { }
for (int i = 0; i < 10; i++) { }

大括号

java
// ✅ K&R 风格:左大括号不换行
public void method() {
    if (condition) {
        // ...
    } else {                              // else 与右大括号同行
        // ...
    }
}

// ❌ Allman 风格(左大括号换行)不推荐
public void method()
{
    if (condition)
    {
        // ...
    }
}

行长度

java
// ✅ 单行不超过 120 字符(IDE 自动换行)
// ✅ 字符串拼接用 + 或 String.join,复杂场景用 StringBuilder
String message = String.format(
    "用户 [%s] 在 [%s] 登录失败,错误码 [%d]",
    username,
    LocalDateTime.now(),
    errorCode
);

空行

java
// ✅ 方法之间空一行
public void method1() { }

// ✅ 类成员之间空一行(字段、构造器、方法分组)
public class UserService {
    private static final Logger log = LoggerFactory.getLogger(UserService.class);

    private final UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User getById(Long id) {
        return userDao.selectById(id);
    }
}

异常处理规范

✅ 使用具体异常,不用通用 Exception

java
try {
    userService.create(user);
} catch (BusinessException e) {            // ✅ 捕获业务异常
    return Result.fail(e.getCode(), e.getMessage());
} catch (DataAccessException e) {          // ✅ 捕获数据访问异常
    log.error("创建用户失败", e);
    return Result.fail("DB_ERROR", "系统繁忙");
}

❌ 反例

java
try {
    userService.create(user);
} catch (Exception e) {                    // ❌ 太宽泛,可能掩盖严重错误
    e.printStackTrace();                   // ❌ 不能用 printStackTrace,应用日志框架
}

注释 vs 日志

java
// ❌ 反例:注释里写操作步骤
public void save() {
    // 1. 校验参数
    validate();
    // 2. 保存到数据库
    dao.save();
    // 3. 发送通知
    notify();
}

// ✅ 正例:注释解释"为什么",方法名解释"做了什么"
public void save() {
    validate();                // 校验放最前,失败快速返回(Fail-Fast)
    dao.save();
    notify();                  // 通知失败不影响主流程(最终一致性)
}

import 顺序

java
// 1. JDK 自带
import java.util.List;
import java.time.LocalDateTime;

// 2. 第三方框架
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.annotation.TableName;

// 3. 本项目内部
import com.taskflow.rbac.entity.User;
import com.taskflow.rbac.service.UserService;

// 4. 静态导入放最后(如果使用)
import static java.lang.Math.PI;

IDEA 默认可以自动排序 import,建议开启 "Optimize imports on the fly"。

命名一致性原则

一个项目里,同一个概念用同一个名字

java
// ❌ 一个文件里 user、usr、userInfo 混用
User user = getUser();
User usr = getUsrById(id);
UserInfo info = getUserInfoByName(name);

// ✅ 全项目统一用 user
User user = getUser();
User userById = getUserById(id);
User userByName = getUserByName(name);

一行不超过一个语句

java
// ❌ 反例
int a = 1; int b = 2;

// ✅ 正例
int a = 1;
int b = 2;

不要省略大括号

java
// ❌ 反例(即使一行也不要省)
if (condition) doSomething();

// ✅ 正例
if (condition) {
    doSomething();
}

原因:未来加一行时容易漏加大括号,导致 bug。

方法长度

  • ✅ 单个方法不超过 80 行(屏幕一屏能看完)
  • ✅ 超过就拆分,提取私有方法
  • ✅ 拆分的原则:一个方法只做一件事
java
// ❌ 反例:一个方法 200 行
public void processOrder(Order order) {
    // 校验参数...
    // 计算价格...
    // 扣库存...
    // 创建订单...
    // 发送通知...
    // 记录日志...
}

// ✅ 正例:拆分为多个方法
public void processOrder(Order order) {
    validateOrder(order);
    BigDecimal price = calculatePrice(order);
    deductInventory(order, price);
    createOrder(order, price);
    notifyAfterOrderCreated(order);
}

工具配置建议

IDEA 必备插件

插件作用
Alibaba Java Coding Guidelines阿里规约实时检查
SonarLint代码质量检查
Lombok Helper简化样板代码
MyBatisXMyBatis 跳转
GitToolBoxGit 状态栏
Rainbow Brackets彩虹括号(嵌套多了很有用)
Translation翻译选中文字

IDEA 关键配置

File → Settings → Editor → Code Style → Java:
- Tab/Indent: Use tab character = OFF, Indent = 4, Continuation indent = 8
- Wrapping and Braces: Braces placement = Same line
- Imports: Class count to use import with '*' = 99
- Import order: 按上面 4 组顺序配置

File → Settings → Editor → File Encodings:
- Global Encoding: UTF-8
- Project Encoding: UTF-8
- Default encoding for properties: UTF-8

以上就是本教程的代码规范。后续所有章节的代码都会遵循这些约定。

如果你已经掌握这些规范,可以开始 第 1 章:为什么学 Java 了。

本站基于 VitePress 构建 · 由 Codebook 团队维护