重构手法——函数行为重塑类 | 语意 | 用Stream管道替换循环

68 阅读2分钟

简介

"用管道替换循环"是现代编程中提升代码可读性的重要重构手法。通过将传统的循环结构转换为声明式的流式管道操作,可以更清晰地表达数据处理逻辑,并天然支持并行化处理。

针对的症状(代码坏味道)

  • 包含复杂条件判断的循环结构
  • 多层嵌套的循环处理
  • 需要维护中间变量的迭代逻辑
  • 包含过滤、映射等常见集合操作

用管道替换循环的详细步骤

  1. 识别循环模式
    • 查找集合遍历操作
    • 识别过滤、映射、聚合等操作
  2. 创建流管道
    • 将集合转换为Stream对象
    • 按步骤分解循环体逻辑
  3. 替换中间变量
    • 用peek()替代临时变量调试
    • 用collect()替代结果收集
  4. 重构异常处理
    • 将循环内的try-catch转换为流式处理
    • 使用Optional处理空值

示例

重构前代码:

List<String> getValidNames(List<Person> people) {
    List<String> result = new ArrayList<>();
    for (Person p : people) {
        if (p != null && p.getAge() >= 18) {
            String name = p.getName().trim();
            if (!name.isEmpty()) {
                result.add(name.toUpperCase());
            }
        }
    }
    return result;
}

重构步骤:

  1. 转换为流管道:

    List<String> getValidNames(List<Person> people) {
        return people.stream()
                .filter(p -> p != null && p.getAge() >= 18)
                .map(p -> p.getName().trim())
                .filter(name -> !name.isEmpty())
                .map(String::toUpperCase)
                .collect(Collectors.toList());
    }
    

练习

基础练习题

  1. 简单循环转换

    // 重构前
    List<Integer> getEvenNumbers(List<Integer> numbers) {
        List<Integer> evens = new ArrayList<>();
        for (Integer n : numbers) {
            if (n % 2 == 0) {
                evens.add(n);
            }
        }
        return evens;
    }
    

进阶练习题

  1. 嵌套循环处理

    // 重构前
    Set<String> getAllEmails(List<Department> departments) {
        Set<String> emails = new HashSet<>();
        for (Department dept : departments) {
            for (Employee emp : dept.getEmployees()) {
                if (emp.getEmail() != null) {
                    emails.add(emp.getEmail().toLowerCase());
                }
            }
        }
        return emails;
    }
    

综合拓展练习题

  1. 复杂业务逻辑重构

    // 重构前
    Map<String, Double> getProductStats(List<Order> orders) {
        Map<String, Double> stats = new HashMap<>();
        for (Order order : orders) {
            if (order.isValid()) {
                for (Item item : order.getItems()) {
                    if (item.getCategory().equals("Electronics")) {
                        double total = stats.getOrDefault(item.getName(), 0.0);
                        total += item.getPrice() * item.getQuantity();
                        stats.put(item.getName(), total);
                    }
                }
            }
        }
        return stats;
    }
    

代码审查要点

  1. 优点:

    • 提升代码可读性
    • 隐含的并行处理能力
    • 减少临时变量使用
  2. 潜在问题:

    • 注意流操作的顺序影响
    • 避免在流中修改外部状态
    • 处理并行流的线程安全问题