Java核心技能实战:从零构建高可维护性代码的5个关键实践

2次阅读
没有评论

共计 2480 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

问题场景

  1. 接手过别人写的代码吗?修改一个变量可能引发三个隐藏 bug,这就是典型的『面条式代码』后遗症。
  2. 当新增需求需要翻遍 20 个类才能找到切入点时,团队开发效率会呈指数级下降。
  3. 生产环境出现 NullPointerException 却找不到调用链?缺乏规范化的异常处理让故障排查变成大海捞针。

优化方案(含对比代码)

1. 语义化命名与 Enum 实战

反面案例

// 难以理解的魔法数字和缩写
public void process(int t, String n) {if (t == 1) {System.out.println(n + "_A");
    } else if (t == 2) {System.out.println(n + "_B");
    }
}

Java 核心技能实战:从零构建高可维护性代码的 5 个关键实践

优化方案

// 使用 Enum 限定类型范围,参数名自解释
public enum ProcessType {
    EXPORT_PDF,  // PDF 导出
    GENERATE_REPORT  // 报告生成
}

public void processDocument(ProcessType processType, String fileName) {switch (processType) {case EXPORT_PDF -> System.out.println(fileName + ".pdf");
        case GENERATE_REPORT -> System.out.println(fileName + "_report.xlsx");
    }
}

2. 单一职责方法设计

反面案例

// 一个方法完成用户创建、校验、日志记录所有操作
public void createUser(String username, String password) {
    // 校验逻辑(50 行代码)// 密码加密(30 行代码)// 数据库操作(40 行代码)// 发送欢迎邮件(20 行代码)}

优化方案

// 每个方法只做一件事(圈复杂度 <5)public User createUser(UserDto userDto) {validateUser(userDto);
    User user = convertToEntity(userDto);
    saveUser(user);
    sendWelcomeEmail(user);
    return user;
}

private void validateUser(UserDto dto) {/* 仅参数校验 */}
private User convertToEntity(UserDto dto) {/* 仅对象转换 */}
// 其他方法同理...

3. 防御性异常处理

反面案例

// 直接吞噬异常导致问题被掩盖
try {FileUtils.readFile(new File("config.txt"));
} catch (Exception e) {e.printStackTrace(); // 仅打印不处理
}

优化方案

// 契约式编程:明确声明可能抛出的异常
public AppConfig loadConfig() throws ConfigNotFoundException, ConfigParseException {
    try {String content = FileUtils.readFile(configPath);
        return parseConfig(content);
    } catch (FileNotFoundException e) {throw new ConfigNotFoundException("配置文件缺失", e);
    } catch (JsonParseException e) {throw new ConfigParseException("配置格式错误", e);
    }
}

4. JUnit5 参数化测试

@ParameterizedTest
@CsvSource({
    "1, true",  // 奇数用例
    "2, false"  // 偶数用例
})
void shouldCheckOddNumber(int input, boolean expected) {assertEquals(expected, NumberUtils.isOdd(input));
}

// 测试数据与逻辑分离
@ParameterizedTest
@MethodSource("provideUserAgeData")
void shouldValidateUserAge(int age, boolean valid) {assertEquals(valid, UserValidator.isAdult(age));
}

private static Stream<Arguments> provideUserAgeData() {
    return Stream.of(Arguments.of(17, false), // 未成年
        Arguments.of(18, true)   // 刚成年
    );
}

5. SLF4J 日志最佳实践

// 错误示范
logger.info("User" + username + "login from" + ip); // 字符串拼接开销

// 正确姿势(使用占位符)logger.info("User {} login from {}", username, ip);

// MDC 实现请求链路追踪
try (MDC.MDCCloseable closeable = MDC.putCloseable("traceId", UUID.randomUUID().toString())) {logger.debug("Start processing order");
    orderService.process();
    logger.debug("Order processed successfully");
}

避坑指南

代码坏味道自查清单

  • [] 方法超过 50 行或圈复杂度 >10
  • [] 存在以 tmp/data 命名的变量
  • [] catch 块中没有记录异常日志
  • [] 测试类覆盖率 <70%
  • [] 同一功能在多处重复实现
  • [] 日志中存在 System.out.println

延伸思考题

  1. 当方法参数超过 5 个时,应该用什么 SOLID 原则进行优化?
  2. 如何通过日志分析定位接口性能瓶颈?
  3. 在微服务架构下,MDC 如何实现跨服务调用链追踪?

小贴士:在 IntelliJ 中安装 SonarLint 插件,可以实时检测上述代码坏味道。

正文完
 0
评论(没有评论)