Java随谈(七)代码优化思路之用空间换时间

前言

在计算机之中,用“空间换时间”是计算机一个常用的优化策略。
本文通过java语言和项目开发的例子,更加深入地理解这个概念

例子说明

Java语言中使用空间换时间的例子

  1. Integer类中,IntegerCache预缓存-128到127的整数对象。
  2. ThreadLocal,‌每个 Thread 内部维护一个 ThreadLocalMap,存储该线程独有的变量副本‌。常用于连接池的线程绑定、日志追踪 ID等。注:ThreadLocal的变量使用完需主动remove。
  3. 不单独创建线程,而是通过管理线程池使用线程资源。

项目开发中使用空间换时间的例子

下面我用简单的几个来进行说明。

  1. 使用额外空间减少重复计算

public class SpaceTimeExample {
    // 递归版本(指数级)
    public static long fibonacciRecursive(int n) {
        if (n <= 1) return n;
        return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2);
    }

    // 缓存版本(线性)
    public static long fibonacciCached(int n) {
        // 使用额外空间存储中间结果
        long[] fib = new long[n + 1];
        fib[0] = 0L; fib[1] = 1L;
        for (int i = 2; i <= n; i++) {
            // 避免重复计算
            fib[i] = fib[i - 1] + fib[i - 2];
        }
        return fib[n];
    }

    // 性能测试(n=40)
    public static void main(String[] args) {
        int n = 40;

        long start = System.nanoTime();
        long result1 = fibonacciRecursive(n);
        long time1 = System.nanoTime() - start;

        start = System.nanoTime();
        long result2 = fibonacciCached(n);
        long time2 = System.nanoTime() - start;

        System.out.printf("递归版本: %d ns (%.2f 秒)%n", time1, time1 / 1e9);
        System.out.printf("缓存版本: %d ns (%.2f 毫秒)%n", time2, time2 / 1e6);
        System.out.printf("性能提升: %.0f 倍%n", (double) time1 / time2);
    }
}

在我的电脑上(Apple M1 芯片,16G内存)
递归版本: 293748834 ns (0.29 秒)
缓存版本: 13750 ns (0.01 毫秒)
性能提升: 21364 倍
2. 用字典表减少查询次数

public enum StatusEnum {
        DRAFT("草稿"),
        PENDING("待审批"),
        APPROVED("审批通过"),
        REJECTED("审批拒绝"),
        WITHDRAW("主动取消"),
        FROZEN("已冻结"),
        ;

        /**
         * 说明
         */
        private final String desc;

        StatusEnum(String desc) {
            this.desc = desc;
        }

        public String getDesc() {
            return desc;
        }

        /**
         * 可以再次提交审批的状态
         */
        public Boolean canReApprovedStatus(StatusEnum status) {
            if (StatusEnum.DRAFT == status || StatusEnum.REJECTED == status || StatusEnum.WITHDRAW == status) {
                return true;
            } else {
                return false;
            }
        }

        /**
         * 通过空间换时间的版本, 将可以再次提交审批的状态存入字典
         */
        public static final Set<StatusEnum> CAN_RE_APPROVED_STATUS_SET =
                EnumSet.of(StatusEnum.DRAFT, StatusEnum.REJECTED, StatusEnum.WITHDRAW);
        public static Boolean betterCanReApprovedStatus(StatusEnum status) {
            return CAN_RE_APPROVED_STATUS_SET.contains(status);
        }
    }
  1. 预加载资源
    /**
     * 预编译正整数的正则
     */
    public static final Pattern PATTERN = Pattern.compile("^\\d+$");

    public static Boolean match(String number) {
        return PATTERN.matcher(number).matches();
    }

    public static void main(String[] args) {
        String number = "123.45";
        System.out.printf("该数字:%s是否为正整数:%s%n", number, match(number));

        String number2 = "123";
        System.out.printf("该数字:%s是否为正整数:%s%n", number2, match(number2));
    }

适用场景

  1. 数据查询重复率高
  2. 数据占用空间有限,不会引起OOM
  3. 代码高频访问,优化后提升明显

风险

  1. 在内存稀缺的场景下(如嵌入式开发)容易引发OOM,在原始数据量巨大的情况下,可能会耗尽内存。
  2. 若源数据重复率很低,大量的数据冷启动容易引起内存等资源的浪费。
posted @ 2026-08-13 02:25  Kwanwooo  阅读(2)  评论(0)    收藏  举报