代码不仅要能正确运行,更要易于阅读、维护和扩展。本文将分享我在两年工作中养成的具体代码优化习惯,包括命名规范、函数设计、消除重复、注释写法、测试策略等实用技巧,每个习惯都配有具体的"Before/After"代码示例。

1. 命名:名副其实,见名知意

坏味道:

// 模糊的命名
public List<int[]> getData() {
    List<int[]> list = new ArrayList<>();
    for (int[] x : theList) {
        if (x[0] == 4) {
            list.add(x);
        }
    }
    return list;
}

优化后:

// 清晰的命名
public List<Cell> getFlaggedCellsOnGameBoard() {
    List<Cell> flaggedCells = new ArrayList<>();
    for (Cell cell : gameBoard) {
        if (cell.isFlagged()) {
            flaggedCells.add(cell);
        }
    }
    return flaggedCells;
}

命名原则实践:

  • 变量名要能表达"是什么",而不是"怎么做"
  • 避免使用datainfotmp等模糊词汇
  • 方法名用动词开头,表达"做什么"
  • 布尔变量/方法用ishascan等前缀

2. 函数:短小精悍,单一职责

坏味道(长函数,多重职责):

public void processUserOrder(String filePath) {
    // 读取文件
    try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
        String line;
        while ((line = br.readLine()) != null) {
            String[] data = line.split(",");
            if (data.length >= 5) {
                String orderId = data[0];
                String userId = data[1];
                BigDecimal amount = new BigDecimal(data[2]);
                String status = data[3];
                Date createTime = parseDate(data[4]);
                
                // 验证数据
                if (isValidOrderId(orderId) && isValidAmount(amount) && isValidStatus(status)) {
                    // 保存订单
                    Order order = new Order(orderId, userId, amount, status, createTime);
                    orderMapper.insert(order);
                    
                    // 更新用户统计
                    userStatsMapper.incrementOrderCount(userId);
                    
                    // 发送订单创建事件
                    eventPublisher.publishEvent(new OrderCreatedEvent(order));
                    
                    // 记录操作日志
                    operationLogService.logOrderCreation(order);
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

优化后(分解为单一职责的小函数):

public void processUserOrder(String filePath) {
    List<String> fileLines = readAllLinesSafely(filePath);
    fileLines.stream()
            .map(this::parseOrderFromCsvLine)
            .filter(Optional::isPresent)
            .map(Optional::get)
            .filter(this::isValidOrder)
            .forEach(this::processValidOrder);
}

private List<String> readAllLinesSafely(String filePath) {
    try {
        return Files.readAllLines(Paths.get(filePath));
    } catch (IOException e) {
        log.error("读取文件失败: {}", filePath, e);
        return Collections.emptyList();
    }
}

private Optional<Order> parseOrderFromCsvLine(String csvLine) {
    try {
        String[] data = csvLine.split(",");
        if (data.length >= 5) {
            Order order = Order.builder()
                    .orderId(data[0])
                    .userId(data[1])
                    .amount(new BigDecimal(data[2]))
                    .status(data[3])
                    .createTime(parseDate(data[4]))
                    .build();
            return Optional.of(order);
        }
    } catch (Exception e) {
        log.warn("解析CSV行失败: {}", csvLine, e);
    }
    return Optional.empty();
}

private boolean isValidOrder(Order order) {
    return isValidOrderId(order.getOrderId()) 
            && isValidAmount(order.getAmount()) 
            && isValidStatus(order.getStatus());
}

private void processValidOrder(Order order) {
    saveOrderToDatabase(order);
    updateUserOrderStatistics(order.getUserId());
    publishOrderCreatedEvent(order);
    logOrderCreationOperation(order);
}

// 每个函数只做一件事
private void saveOrderToDatabase(Order order) {
    orderMapper.insert(order);
}

private void updateUserOrderStatistics(String userId) {
    userStatsMapper.incrementOrderCount(userId);
}

private void publishOrderCreatedEvent(Order order) {
    eventPublisher.publishEvent(new OrderCreatedEvent(order));
}

private void logOrderCreationOperation(Order order) {
    operationLogService.logOrderCreation(order);
}

3. 消除重复:DRY原则的实际应用

坏味道(重复的校验逻辑):

@Service
public class UserService {
    public void createUser(User user) {
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        if (user.getUsername().length() < 3 || user.getUsername().length() > 20) {
            throw new IllegalArgumentException("用户名长度必须在3-20之间");
        }
        if (!user.getUsername().matches("^[a-zA-Z0-9_]+$")) {
            throw new IllegalArgumentException("用户名只能包含字母、数字和下划线");
        }
        // ... 重复的邮箱校验逻辑
        // ... 重复的手机号校验逻辑
    }
    
    public void updateUser(User user) {
        // 重复的用户名校验逻辑
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        // ... 其他重复逻辑
    }
}

优化后(使用注解校验和统一处理):

// 使用Validation注解定义规则
@Data
public class User {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
    @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
    private String username;
    
    @Email(message = "邮箱格式不正确")
    @NotBlank(message = "邮箱不能为空")
    private String email;
    
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
}

// 统一的校验工具类
@Component
public class ValidationUtils {
    
    public void validate(Object object) {
        Set<ConstraintViolation<Object>> violations = Validation.buildDefaultValidatorFactory()
                .getValidator()
                .validate(object);
        
        if (!violations.isEmpty()) {
            String errorMessage = violations.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining("; "));
            throw new ValidationException(errorMessage);
        }
    }
}

// 简洁的业务代码
@Service
@Validated
public class UserService {
    
    @Autowired
    private ValidationUtils validationUtils;
    
    public void createUser(@Valid User user) {
        // Spring会自动校验@Valid注解的参数
        userMapper.insert(user);
    }
    
    public void updateUser(User user) {
        validationUtils.validate(user); // 手动校验
        userMapper.update(user);
    }
}

4. 注释的艺术:解释为什么,而不是是什么

坏注释:

// 计算面积
public double calculateArea(double radius) {
    return 3.14 * radius * radius; // πr²
}

// 设置用户状态
public void setUserStatus(int status) {
    this.status = status;
}

好注释:

/**
 * 使用蒙特卡洛方法估算π值
 * 这种方法在精度要求不高但计算资源有限时使用
 * 参考: https://en.wikipedia.org/wiki/Monte_Carlo_method
 */
public double estimatePi(int sampleCount) {
    // 实现细节...
}

/**
 * 设置用户状态,注意:
 * 1. 状态从0变为1时会触发欢迎流程
 * 2. 状态从1变为2时需要检查是否满足升级条件
 * 3. 状态变为99时不可逆转
 */
public void setUserStatus(UserStatus status) {
    UserStatus oldStatus = this.status;
    this.status = status;
    publishStatusChangeEvent(oldStatus, status);
}

5. 测试策略:可测试的代码设计

难以测试的代码:

@Service
public class OrderService {
    
    @Autowired
    private EmailService emailService;
    
    public void createOrder(Order order) {
        // 直接依赖具体实现,难以mock
        if (order.getAmount().compareTo(BigDecimal.ZERO) > 0) {
            emailService.sendOrderConfirmation(order.getEmail(), order);
        }
        orderMapper.insert(order);
    }
}

易于测试的代码:

// 定义接口
public interface NotificationService {
    void sendOrderConfirmation(String email, Order order);
}

@Service
public class EmailService implements NotificationService {
    @Override
    public void sendOrderConfirmation(String email, Order order) {
        // 具体实现
    }
}

// 通过构造函数注入依赖
@Service
public class OrderService {
    
    private final OrderMapper orderMapper;
    private final NotificationService notificationService;
    
    // 构造函数注入,依赖关系明确
    public OrderService(OrderMapper orderMapper, NotificationService notificationService) {
        this.orderMapper = orderMapper;
        this.notificationService = notificationService;
    }
    
    public void createOrder(Order order) {
        if (shouldSendConfirmation(order)) {
            notificationService.sendOrderConfirmation(order.getEmail(), order);
        }
        orderMapper.insert(order);
    }
    
    // 将条件判断提取为方法,便于测试
    boolean shouldSendConfirmation(Order order) {
        return order.getAmount().compareTo(BigDecimal.ZERO) > 0;
    }
}

// 单元测试
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    
    @Mock
    private OrderMapper orderMapper;
    
    @Mock
    private NotificationService notificationService;
    
    @InjectMocks
    private OrderService orderService;
    
    @Test
    void shouldSendConfirmationWhenOrderAmountIsPositive() {
        // Given
        Order order = Order.builder()
                .amount(new BigDecimal("100.00"))
                .email("test@example.com")
                .build();
        
        // When
        orderService.createOrder(order);
        
        // Then
        verify(notificationService).sendOrderConfirmation("test@example.com", order);
        verify(orderMapper).insert(order);
    }
    
    @Test
    void shouldNotSendConfirmationWhenOrderAmountIsZero() {
        // Given
        Order order = Order.builder()
                .amount(BigDecimal.ZERO)
                .email("test@example.com")
                .build();
        
        // When
        orderService.createOrder(order);
        
        // Then
        verify(notificationService, never()).sendOrderConfirmation(anyString(), any());
        verify(orderMapper).insert(order);
    }
}

6. 使用现代Java特性简化代码

使用Stream API替代循环:

// 传统方式
List<String> activeUserNames = new ArrayList<>();
for (User user : users) {
    if (user.isActive() && user.getCreateTime().after(lastMonth)) {
        activeUserNames.add(user.getName().toUpperCase());
    }
}

// Stream方式
List<String> activeUserNames = users.stream()
        .filter(User::isActive)
        .filter(user -> user.getCreateTime().after(lastMonth))
        .map(User::getName)
        .map(String::toUpperCase)
        .collect(Collectors.toList());

使用Optional避免空指针:

// 传统方式
public String getManagerName(Department department) {
    if (department != null) {
        Employee manager = department.getManager();
        if (manager != null) {
            return manager.getName();
        }
    }
    return "未知";
}

// Optional方式
public String getManagerName(Department department) {
    return Optional.ofNullable(department)
            .map(Department::getManager)
            .map(Employee::getName)
            .orElse("未知");
}

7. 代码审查清单:我常用的检查点

在代码审查时,我通常会检查以下方面:

  • [ ] 命名是否清晰表达了意图?
  • [ ] 函数是否短小且只做一件事?
  • [ ] 是否有重复代码可以抽取?
  • [ ] 异常处理是否完善?
  • [ ] 日志记录是否恰当?
  • [ ] 测试是否覆盖了主要场景?
  • [ ] 是否有明显的性能问题?
  • [ ] 是否考虑了线程安全?
  • [ ] 配置参数是否可外部化?
  • [ ] 文档注释是否完善?

总结:

两年的编程实践让我深刻认识到,​编写可工作的代码只是基础,编写可维护、可测试、可扩展的代码才是专业程序员的追求​。这些代码优化习惯不是一蹴而就的,而是需要在日常开发中不断实践和反思。每次代码审查、每次生产问题排查,都是改进代码质量的机会。良好的代码习惯就像肌肉记忆一样,需要持续锻炼才能形成。

如果觉得我的文章对你有用,请随意赞赏