Java随谈(七)代码优化思路之用空间换时间
前言
在计算机之中,用“空间换时间”是计算机一个常用的优化策略。
本文通过java语言和项目开发的例子,更加深入地理解这个概念
例子说明
Java语言中使用空间换时间的例子
- Integer类中,IntegerCache预缓存-128到127的整数对象。
- ThreadLocal,每个 Thread 内部维护一个 ThreadLocalMap,存储该线程独有的变量副本。常用于连接池的线程绑定、日志追踪 ID等。注:ThreadLocal的变量使用完需主动remove。
- 不单独创建线程,而是通过管理线程池使用线程资源。
项目开发中使用空间换时间的例子
下面我用简单的几个来进行说明。
- 使用额外空间减少重复计算
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);
}
}
- 预加载资源
/**
* 预编译正整数的正则
*/
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));
}
适用场景
- 数据查询重复率高
- 数据占用空间有限,不会引起OOM
- 代码高频访问,优化后提升明显
风险
- 在内存稀缺的场景下(如嵌入式开发)容易引发OOM,在原始数据量巨大的情况下,可能会耗尽内存。
- 若源数据重复率很低,大量的数据冷启动容易引起内存等资源的浪费。

浙公网安备 33010602011771号