如何避免写垃圾代码:Java篇

如何避免写垃圾代码:Java篇

引言

Linux和Git的创建者Linus Torvalds曾严厉批评了一位Meta工程师提交的代码,称其增加了"无意义的抽象"和"垃圾代码"。这一事件揭示了软件工程中的一个核心原则:优秀代码应该最小化认知负荷

在Java开发中,这一原则尤为重要。本文将通过具体示例,探讨如何在Java中避免编写"垃圾代码"。

1. 避免不必要的抽象

反例:过度封装

java 复制代码
// 垃圾代码:无意义的抽象
public class NumberHelper {
    public static int makeIntFromTwoShorts(short high, short low) {
        return (high << 16) | (low & 0xffff);
    }
}

// 使用方式
int result = NumberHelper.makeIntFromTwoShorts(highValue, lowValue);

正例:直接清晰的表达

java 复制代码
// 好代码:直接表达意图
int result = (highValue << 16) | (lowValue & 0xffff);

知识点:只有当抽象真正减少复杂性时才使用它。直接使用位操作比调用一个意义不明的辅助方法更清晰。

2. 减少上下文切换

反例:过度分散的逻辑

java 复制代码
// 垃圾代码:需要跨多个文件理解
public class OrderProcessor {
    public void processOrder(Order order) {
        if (ValidationHelper.isValid(order)) {
            PricingHelper.calculatePrice(order);
            InventoryHelper.updateInventory(order);
            NotificationHelper.sendConfirmation(order);
        }
    }
}

正例:保持逻辑局部性

java 复制代码
// 好代码:自包含的逻辑
public class OrderProcessor {
    public void processOrder(Order order) {
        if (isValid(order)) {
            calculatePrice(order);
            updateInventory(order);
            sendConfirmation(order);
        }
    }
    
    private boolean isValid(Order order) {
        return order != null && order.getItems() != null && !order.getItems().isEmpty();
    }
    
    private void calculatePrice(Order order) {
        // 直接计算价格的逻辑
        double total = order.getItems().stream()
            .mapToDouble(item -> item.getPrice() * item.getQuantity())
            .sum();
        order.setTotalPrice(total);
    }
    
    // 其他方法也保持在同一个类中
}

知识点:人类大脑的工作记忆有限(4-7个信息块)。保持相关代码在视觉上接近,减少文件间跳转,可以显著降低认知负荷。

3. 明智地对待DRY原则

反例:盲目遵循DRY

java 复制代码
// 垃圾代码:过度抽象导致困惑
public class StringHelper {
    public static String concatenateWithDelimiter(String str1, String str2, String delimiter) {
        return str1 + delimiter + str2;
    }
}

// 在代码中多处使用
String fullName = StringHelper.concatenateWithDelimiter(firstName, lastName, " ");
String address = StringHelper.concatenateWithDelimiter(street, city, ", ");

正例:适当重复以提高清晰度

java 复制代码
// 好代码:直接拼接更清晰
String fullName = firstName + " " + lastName;
String address = street + ", " + city;

知识点PRY(Please Repeat Yourself)原则有时比DRY更重要。简单的字符串拼接不需要抽象成辅助方法。

4. 命名即文档

反例:模糊的命名

java 复制代码
// 垃圾代码:命名没有提供有用信息
public class Helper {
    public static void processData(List<Object> data) {
        // 处理逻辑
    }
}

正例:清晰的命名

java 复制代码
// 好代码:命名准确描述功能
public class OrderValidator {
    public static void validateInventoryAvailability(List<OrderItem> orderItems) {
        // 验证逻辑
    }
}

知识点:Java开发者依赖IDE的自动完成和代码提示。好的命名可以减少查看方法实现的需要。

5. 谨慎使用设计模式

反例:模式滥用

java 复制代码
// 垃圾代码:过度工程化
public interface DataProcessor {
    void process();
}

public abstract class AbstractDataProcessor implements DataProcessor {
    // 多层抽象
}

public class ConcreteDataProcessor extends AbstractDataProcessor {
    @Override
    public void process() {
        // 实际处理逻辑
    }
}

// 还需要工厂类来创建实例

正例:简单直接的设计

java 复制代码
// 好代码:需要时再引入模式
public class DataProcessor {
    public void processData() {
        // 直接实现处理逻辑
    }
}

知识点:YAGNI原则(You Aren't Gonna Need It)------不要为未来可能需要的功能添加抽象,等到真正需要时再重构。

6. 适应AI编程新时代

随着AI编程助手(如GitHub Copilot、Amazon CodeWhisperer)的普及,代码的可预测性和局部性变得更加重要。

反例:AI不友好的代码

java 复制代码
// 垃圾代码:逻辑分散,AI难以理解完整上下文
public class Service {
    public void execute() {
        Helper.doSomething(this.data);
    }
}

// 在另一个文件中
public class Helper {
    public static void doSomething(Data data) {
        // 复杂的逻辑
        AnotherHelper.doMore(data);
    }
}

正例:AI友好的代码

java 复制代码
// 好代码:自包含的方法
public class Service {
    public void execute() {
        doSomethingWithData(data);
    }
    
    private void doSomethingWithData(Data data) {
        // 完整的逻辑在同一方法中
        validateData(data);
        processData(data);
        updateData(data);
    }
    
    private void validateData(Data data) {
        // 验证逻辑
    }
    
    private void processData(Data data) {
        // 处理逻辑
    }
    
    private void updateData(Data data) {
        // 更新逻辑
    }
}

知识点:AI工具的上下文窗口有限。保持相关代码在同一个上下文中,可以提高AI生成代码的质量。

7. 性能与可读性的平衡

反例:过度优化降低可读性

java 复制代码
// 垃圾代码:为了微小性能提升牺牲可读性
public class OptimizedCalculator {
    public static int calculate(int[] values) {
        int result = 0;
        for (int i = 0; i < values.length; i++) {
            result += values[i] * (i % 2 == 0 ? 2 : 3) + (i > 5 ? values[i] / 2 : 0);
        }
        return result;
    }
}

正例:清晰第一,优化第二

java 复制代码
// 好代码:清晰表达意图,必要时再优化
public class ClearCalculator {
    public static int calculate(int[] values) {
        int sum = 0;
        
        for (int i = 0; i < values.length; i++) {
            int multiplier = (i % 2 == 0) ? 2 : 3;
            int bonus = (i > 5) ? values[i] / 2 : 0;
            
            sum += values[i] * multiplier + bonus;
        }
        
        return sum;
    }
}

知识点:现代JVM的JIT编译器非常智能,通常能够优化清晰的代码。可读性差的代码反而可能阻碍编译器的优化能力。

总结:写好Java代码的关键原则

  1. 最小化认知负荷:让代码容易被人类和AI理解
  2. 保持局部性:相关代码保持接近,减少文件间跳转
  3. 命名即文档:使用清晰准确的命名表达意图
  4. 谨慎抽象:只在抽象真正减少复杂性时使用
  5. 适度重复:有时重复比错误的抽象更好
  6. 渐进复杂:需要时再引入模式,而不是预先过度设计
  7. 清晰优于巧妙:可读性比微小性能提升更重要

原文:xuanhu.info/projects/it...

相关推荐
vker2 小时前
第 1 天:单例模式(Singleton Pattern)—— 创建型模式
java·设计模式
无限大62 小时前
HTTP 1.0去哪了?揭开Web协议版本误解的真相
后端·面试
程序员蜗牛2 小时前
![图片](https://p0-xtjj-private.juejin.cn/tos-cn-i-73owjymdk6/62105da0f2c54b3497b0
后端
他日若遂凌云志2 小时前
深入拆解 Linux Socket 五大 I/O 模型:从底层机制到性能适配
后端
expect7g2 小时前
COW、MOR、MOW
大数据·数据库·后端
我不是混子2 小时前
什么是内存泄漏?
java
程序员小假2 小时前
我们来说说当一个线程两次调用 start() 方法会出现什么情况?
java·后端
bobz9652 小时前
I/O复用 select、poll、epoll
后端
无限大62 小时前
一文读懂HTTP 1.1/2.0/3.0:从原理到应用的通俗解析
后端·面试