代码优化实际案例
一、业务场景
项目中做的一个功能,需要查询几十张表中的数据,然后在处理这些查询出的数据,处理好之后在将数据
按照一定的规则放入缓存当中。做这个操作主要是为了系统迁移的时候使用,在使用新系统的时候,有些缓存
数据可能会丢失,因此需要做这个操作。接到这个任务后,自己稍微分析了一下,然后确定思路,大致思路为:
.1.使用循环查询出所有的列表数据;.2.循环处理数据,将数据放入一个Map容器中,形式为key-value;.3.循环
将数据放入缓存中,完成功能。按照这个思路,自己经过反复调试,最终写的代码如下:
@Slf4j
public class ServiceTest {
public boolean updateTest() {
Map<Integer, List<TransmitActivityTotal>> transmitActivityTotalMap = new HashMap<>(30);
List<TransmitActivityTotal> transmitActivityTotals = null;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
// 查询数据
for(int i = 0; i < 30; i++){
// 根据不同的分表信息查询不同的数据,查询方式省略
transmitActivityTotals = null;
transmitActivityTotalMap.put(i, transmitActivityTotals);
}
// 处理数据
if (transmitActivityTotalMap.isEmpty()) {
return false;
}
Map<Long, Integer> idTotalMap = new HashMap<>();
Integer total = null;
for(Map.Entry<Integer, List<TransmitActivityTotal>> item : transmitActivityTotalMap.entrySet()) {
for(TransmitActivityTotal transmitActivityTotal : item.getValue()) {
total = transmitActivityTotal.getTotal() == null ? Integer.valueOf(0) : transmitActivityTotal.getTotal();
if (idTotalMap.keySet().contains(transmitActivityTotal.getId())) {
// 再次添加 原有数据 + 新数据
idTotalMap.put(transmitActivityTotal.getId(), idTotalMap.get(transmitActivityTotal.getId()) + total);
} else {
// 首次添加
idTotalMap.put(transmitActivityTotal.getId(), total);
}
}
}
for(Map.Entry<Long, Integer> item : idTotalMap.entrySet()) {
// 使用redis进行 恢复缓存 操作
log.info("id-->{}, 数量--->", item.getKey(), item.getValue());
}
stopWatch.stop();
log.info("缓存恢复耗时--->{}毫秒", stopWatch.getLastTaskTimeMillis());
return true;
} catch (Exception ex) {
stopWatch.stop();
log.error("缓存更新异常--->{}", ex);
return false;
}
}
}
@Data
public class TransmitActivityTotal {
/*
* id
*/
private Long id;
/*
* 数量
*/
private Integer total;
}
经过测试,发现这种方式代码能够正常执行,并且符合预期的要求。可是在负责人审核我写的代码的时候,让我好好去检查代码,
看看有没有可以优化的地方。听他这么一说,让我感觉有一丝意外,这已经是最好的代码,还要怎么优化呢?现在是按照步骤
一步一步的执行,整个程序都运行正常,并且也能够实现功能。可是既然负责人都说了,自己也只好继续改进,经过自己不断地
思考,最终想到优化办法。
二、优化方案
最开始的方案是一个步骤一个步骤的进行,可是能不能几个步骤同时进行,这样不仅代码量减少,并且代码也更加地容易理解。
说干就干,一直朝着这个方向不断地去优化上面的代码,最终优化的代码结果如下:
public boolean updateTest() {
List<TransmitActivityTotal> transmitActivityTotals = null;
StopWatch stopWatch = new StopWatch();
Map<String, Integer> idTotalMap = new HashMap<>();
stopWatch.start();
try {
// 查询数据
for(int i = 0; i < 30; i++){
// 根据不同的分表信息查询不同的数据 数据查询省略
transmitActivityTotals = null;
if (transmitActivityTotals == null || transmitActivityTotals.size() < 1) {
continue;
}
for(TransmitActivityTotal transmitActivityTotal : transmitActivityTotals) {
Integer total = transmitActivityTotal.getTotal() == null ? Integer.valueOf(0) : transmitActivityTotal.getTotal();
if (idTotalMap.keySet().contains(transmitActivityTotal.getId())) {
// 再次添加 原有数据 + 新数据
idTotalMap.put(transmitActivityTotal.getId().toString(), idTotalMap.get(transmitActivityTotal.getId()) + total);
} else {
// 首次添加
idTotalMap.put(transmitActivityTotal.getId().toString(), total);
}
}
}
// 可以一次性添加缓存数据 this.redisTemplate.opsForHash().putAll(key, mapData);
stopWatch.stop();
log.info("缓存恢复耗时--->{}毫秒", stopWatch.getLastTaskTimeMillis());
return true;
} catch (Exception ex) {
stopWatch.stop();
log.error("缓存更新异常--->{}", ex);
return false;
}
}
修改后的代码,大大地减少了代码量,更加容易阅读与理解,看起来也更加地简洁。思路已经简化为查询出代码后,立马
处理数据,存入缓存的方式也修改为一次性存入,而不再是一条一条的存入。简化后的代码在自己看来,好太多,效率也
高很多,减少了两个循环,数据也不用在在存储在一个大的容器中,然后在从容器中取出来。到此代码优化完成!
通过这次代码优化,自己又考虑到另外一个实际的优化案例。有好几个首页的列表查询,思路是:.1.从缓存中获取数据
或者是从数据库查询数据;.2.过滤数据;.3.对数据进行排序;.4.转换数据,将数据转换为需要返回的OutVo类型的数据;
.5.处理数据,比如类型翻译,使用日期做计算操作等等。按照步骤一步一步来,也没问题,最终功能实现。有一次测试负责人
在对我写的接口进行性能测试时,发现性能不达标提出BUG,需要我这边去做优化处理。自己一步一步分析,过滤数据时循环
一次,转换数据时循环一次,数据处理时又循环一次,这些操作能否一次性完成呢?优化后的思路为:.1.从缓存中获取数据或者
是从数据库查询数据;.2.对数据进行排序;.3.过滤、转换、处理数据;按照这种思路来进行修改后,效率果然大大地提升。最终
测试人员的测试结论,效率比之前有很大的提升,完全能够满足系统对性能的要求。
总结:从这两次代码优化中,自己学到一点,有的时候写代码可以按照设计好的思路一步一步来,写好之后,可以考虑某些
步骤是否可以合并完成。如果可以,则将其合并,能够提升代码的运行效率。有其他更好建议的小伙伴,欢迎留言讨论。