代码规范实践:让代码说话
前面我们聊了异常、命名、格式化、集合...
这些规范如果不落地到日常开发中,就只是纸面上的东西。
这一节聊聊怎么在实际项目中真正用起来。
方法设计
好方法的特征:单一职责、参数适量、名字清晰。
方法不要太长
一个方法最好不超过一屏(约 50 行),超长就拆:
java
// ❌ 一个方法做了太多事
public void processOrder(Order order) {
// 校验订单
if (order == null) throw new IllegalArgumentException();
if (order.getItems() == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("订单项不能为空");
}
// 计算价格
double total = 0;
for (OrderItem item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
}
// 应用折扣
if (total > 1000) total *= 0.9;
// 验证库存
for (OrderItem item : order.getItems()) {
if (!inventoryService.checkStock(item)) {
throw new OutOfStockException(item.getProductId());
}
}
// 保存订单
order.setTotal(total);
orderRepository.save(order);
// 发通知
notificationService.sendOrderConfirmation(order);
}
// ✅ 重构后,每个方法只做一件事
public void processOrder(Order order) {
validateOrder(order);
double total = calculateTotal(order);
applyDiscount(total);
checkInventory(order);
saveAndNotify(order);
}参数不宜过多
参数超过 3 个就该考虑用参数对象了:
java
// ❌ 参数过多,调用方痛苦
public void createUser(String firstName, String lastName, String email,
String phone, String address, int age, boolean isActive) {
}
// ✅ 用 DTO
public void createUser(UserCreateDTO dto) {
}注释规范
好注释解释为什么,不解释是什么。代码本身应该自解释。
解释不直观的设计决策
java
// ❌ 注释什么:代码已经说了
// 设置用户名为 zhang
user.setName("zhang");
// ✅ 解释为什么:不能从代码本身看出来的原因
// 密码最小长度 8 位,但考虑到用户习惯,设为 6 位过渡期
private static final int PASSWORD_MIN_LENGTH = 6;
// ✅ 解释魔法值
// 为什么用 86400:每天的秒数
private static final long EXPIRY_DAYS = 7;
private static final long EXPIRY_SECONDS = EXPIRY_DAYS * 24 * 60 * 60; // 604800不要写废话注释
java
// ❌ 废话注释
/**
* Sets the user name.
* @param name the user name
*/
public void setName(String name) {
this.name = name;
}
// ✅ 如果方法名足够清晰,就不需要 Javadoc
public void setName(String name) {
this.name = name;
}
// ✅ 需要给调用方看的复杂逻辑说明,才需要 Javadoc
/**
* 根据传入的优惠码计算折扣。
* 规则:VIP 用户额外 5% 折扣,新用户首单 10 元优惠,
* 两种优惠不叠加,取较大值。
*/
public Discount calculateDiscount(User user, String couponCode) { ... }类设计
单一职责
一个类只做一件事,这样更容易理解、测试和维护:
java
// ❌ 上帝类:所有功能都往里塞
class UserManager {
void createUser() {}
void deleteUser() {}
void sendEmail() {} // 为什么邮件在用户管理里?
void generateReport() {} // 为什么报表也在里面?
}
// ✅ 单一职责
class UserService { void create() {} void delete() {} }
class EmailService { void send() {} }
class ReportService { void generate() {} }优先依赖接口
这样改实现类时调用方不用动:
java
// ✅ 依赖接口
private final UserRepository userRepository; // 接口
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ❌ 依赖具体实现
private final JdbcUserRepository userRepository; // 改成 MyBatis 就得改 Service减少 null 的使用
null 是万恶之源,尽量避免。
用 Optional
java
// ❌ 返回 null,调用方稍不留神就 NPE
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
// ✅ 返回 Optional,让调用方必须处理
public Optional<User> findById(Long id) {
return userRepository.findById(id);
}用空集合代替 null
java
// ❌ 不要返回 null
public List<Order> findOrders(Long userId) {
return null; // ❌
}
// ✅ 返回空集合
public List<Order> findOrders(Long userId) {
return orders; // 返回 Collections.emptyList()
}总结
规范落地的关键:
- 小步重构:每次改一点,保持测试通过
- 代码审查:review 时检查规范执行情况
- 工具辅助:用 Checkstyle、SpotBugs 自动检查
- 写好注释:解释"为什么",而不是"是什么"
代码是写给人看的,顺便让机器执行。
