本来是要修复前一个代码bug,修复的过程中发现原本的代码又丑又长,复用性差(但是能用),出于强迫症忍不住的去优化,测试还不充分,火急火燎的发到生产了,结果掉井了!导致多个订单线下物流发货发多了.... 万一有个别用户不管订单数量是不是自己下单的,直接签收了,再往回要就难了,那时还要加上来回运费。

当时提桶跑路的心都有/(ㄒoㄒ)/~~,但这个东西逃不掉,而且问题越拖越严重。这个时候就不能再去顾虑别人对自己的看法了,事情已经这样了,可奈何 ?不如主动承认错误,尽早解决降低损失。

最后硬着头皮向领导说明了情况,然后联系协助各方人员尽量挽救,将损失降到最低。

整个过程真是自惭形秽,无地自容,恨不能找个地缝钻进去 ...

事后总结:

当时因为需要构建好多场景,嫌麻烦,加上蜜汁自信,测试不充分。

主观上是因为自己对于代码失去了敬畏之心,随意修改,不考虑或者不想考虑如果错了会造成什么样的后果。

对于代码最好的优化就是能跑通就不要优化。如要修改,选择对于已有代码影响最小的方案。

下面模拟这个问题

准备

目的:将集合中重复的元素合并起来

比如:将下面列表 bigHouseList 中相同房屋主人 ownerName 的房屋价值 worth 累加起来

BigHouse house1 = new BigHouse("张三", "别墅", new BigDecimal("2400"), "想不到路-10号");
BigHouse house2 = new BigHouse("赵柳", "公寓", new BigDecimal("120"), "现实路30号");
BigHouse house3 = new BigHouse("李四", "别墅", new BigDecimal("780"), "你别想路-101号");
BigHouse house4 = new BigHouse("王五", "小洋楼", new BigDecimal("8000"), "梦不到路-1000号");
BigHouse house5 = new BigHouse("赵柳", "别墅", new BigDecimal("3500"), "想不到路-28号");
BigHouse house6 = new BigHouse("王五", "别墅", new BigDecimal("4200"), "想不到路-130号"); List<BigHouse> bigHouseList = new ArrayList<>();
bigHouseList.add(house1);
bigHouseList.add(house2);
bigHouseList.add(house3);
bigHouseList.add(house4);
bigHouseList.add(house5);
bigHouseList.add(house6);

**大房子类 BigHouse **

@Data
public class BigHouse {
/**
* 房屋主人名字
*/
private String ownerName; /**
* 房屋类型
*/
private String type; /**
* 房屋价值(单位万)
*/
private BigDecimal worth; /**
* 详细地址
*/
private String address; public BigHouse() {
} public BigHouse(String ownerName, String type, BigDecimal worth, String address) {
this.ownerName = ownerName;
this.type = type;
this.worth = worth;
this.address = address;
}
}

优化前的代码

优化理由:这部分代码逻辑和业务无关,可以抽离出来形成一个公共的方法函数

//region 优化前的代码
List<BigHouse> uniqueOwnerHouseList = new ArrayList<>();
boolean isSameOwner = true;
for (BigHouse house : bigHouseList) {
isSameOwner = Boolean.FALSE;
if (uniqueOwnerHouseList.size() > 0) {
for (BigHouse h : uniqueOwnerHouseList) {
if (h.getOwnerName().equals(house.getOwnerName())) {
h.setWorth(h.getWorth().add(house.getWorth()).setScale(0, BigDecimal.ROUND_HALF_UP));
isSameOwner = Boolean.TRUE;
}
}
}
if (!isSameOwner) {
uniqueOwnerHouseList.add(house);
}
}
//endregion System.out.println("优化前结果输出:");
//优化后结果输出
for (BigHouse bigHouse : uniqueOwnerHouseList) {
System.out.println(bigHouse.getOwnerName() + "坐拥 " + bigHouse.getWorth() + " 万房产!");
}

输出结果:

优化前结果输出:
张三坐拥 2400 万房产!
赵柳坐拥 3620 万房产!
李四坐拥 780 万房产!
王五坐拥 12200 万房产!

优化后的代码(bug)

/**
* 合并集合中重复的元素
*
* @param items
* @param predicate 判断是否重复
* @param consumer 重复后处理
* @param <T>
* @return
*/
public static <T> List<T> mergeDuplicate(Collection<T> items, BiPredicate<T, T> predicate, BiConsumer<T, T> consumer) {
List<T> mergeItems = new ArrayList<>();
for (T item : items) {
boolean existSameItem = false;
for (T mergeItem : mergeItems) {
existSameItem = predicate.test(mergeItem, item);
if (existSameItem) {
consumer.accept(mergeItem, item);
}
}
if (!existSameItem) {
mergeItems.add(item);
}
}
return mergeItems;
} //优化后的代码
List<BigHouse> mergedBigHouseList = CollectionTools.mergeDuplicate(bigHouseList,
(p, n) -> p.getOwnerName().equals(n.getOwnerName()),
(p, n) -> {
p.setWorth(p.getWorth().add(n.getWorth()).setScale(0, BigDecimal.ROUND_HALF_UP));
}
); System.out.println("优化后结果输出:");
for (BigHouse bigHouse : mergedBigHouseList) {
System.out.println(bigHouse.getOwnerName() + "坐拥 " + bigHouse.getWorth() + " 万房产!");
}

输出结果:

优化前结果输出:
张三坐拥 2400 万房产!
赵柳坐拥 3620 万房产!
李四坐拥 780 万房产!
王五坐拥 12200 万房产!
赵柳坐拥 3500 万房产!
王五坐拥 4200 万房产!

逻辑分析

原因出在这块代码上

for (T mergeItem : mergeItems) {
existSameItem = predicate.test(mergeItem, item);
if (existSameItem) {
consumer.accept(mergeItem, item);
}
}

在 if 判断true后,应该break跳出循环的,否则 existSameItem 的值会被 mergeItems 剩余元素的比较结果覆盖掉,从而影响循环外的 if 判断

if (!existSameItem) {
mergeItems.add(item);
}

正确的写法:

for (T mergeItem : mergeItems) {
existSameItem = predicate.test(mergeItem, item);
if (existSameItem) {
consumer.accept(mergeItem, item);
break;
}
}

或者(不建议)

for (T mergeItem : mergeItems) {
if (predicate.test(mergeItem, item);) {
consumer.accept(mergeItem, item);
existSameItem = true;
}
}

【生产事故调查】优化出来的bug-合并集合重复项的更多相关文章

  1. sql分组合并字段重复项sql for xml path

    -------------------------(情景描述) 在我们处理数据时,可能会碰到这种情景: Id                Name 1                  a,b 2  ...

  2. 一次 select for update 的悲观锁使用引发的生产事故

    1.事故描述 本月 8 日上午十点多,我们的基础应用发生生产事故.具体表象为系统出现假死无响应.查看事发时间段的基础应用 error 日志,没发现明显异常.查看基础应用业务日志,银行结果处理的部分普遍 ...

  3. (转)CentOS(5.8/6.4)linux生产环境若干优化实战

    CentOS(5.8/6.4)linux生产环境若干优化实战 原文:http://blog.51cto.com/oldboy/1336488 特别说明:本文来自老男孩linux培训VIP学生学习笔记. ...

  4. 生产事故(MongoDB数据分布不均解决方案)

    可以很明显可以看到我们这个集合的数据严重分布不均匀. 一共有8个分片,面对这个情况我首先想到的是手动拆分数据块,但这不是解决此问题的根本办法. 造成此次生产事故的首要原因就是片键选择上的问题,由于片键 ...

  5. 算法练习之合并两个有序链表, 删除排序数组中的重复项,移除元素,实现strStr(),搜索插入位置,无重复字符的最长子串

    最近在学习java,但是对于数据操作那部分还是不熟悉 因此决定找几个简单的算法写,用php和java分别实现 1.合并两个有序链表 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两 ...

  6. [算法]合并链表&删除数组重复项

    合并链表 题目 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1-> ...

  7. 日常Bug排查-Nginx重复请求?

    日常Bug排查-Nginx重复请求? 前言 日常Bug排查系列都是一些简单Bug排查,笔者将在这里介绍一些排查Bug的简单技巧,其中不乏一些看起来很低级但很容易犯的问题. 问题现场 有一天运维突然找到 ...

  8. 记一次生产事故的排查与优化——Java服务假死

    一.现象 在服务器上通过curl命令调用一个Java服务的查询接口,半天没有任何响应.关于该服务的基本功能如下: 1.该服务是一个后台刷新指示器的服务,即该服务会将用户需要的指示器数据提前计算好,放入 ...

  9. 优化RequireJS项目(合并与压缩)

    关于RequireJS已经有很多文章介绍过了.这个工具可以将你的JavaScript代码轻易的分割成苦 干个模块(module)并且保持你的代码模块化与易维护性.这样,你将获得一些具有互相依赖关系的J ...

随机推荐

  1. CF932G Palindrome Partition(回文自动机)

    CF932G Palindrome Partition(回文自动机) Luogu 题解时间 首先将字符串 $ s[1...n] $ 变成 $ s[1]s[n]s[2]s[n-1]... $ 就变成了求 ...

  2. 一个lseek引起的思考

    先看一段代码: int find_value(int fd) { int ret; char buff[8] = ""; struct timeval st,ed; long lo ...

  3. HTTP与HTTPS有什么区别

    超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂 ...

  4. springboot 配置文件的优先级和互补配置

    一.springboot启动时候,配置文件的优先级如下所示由高到低.高优先级会覆盖低优先级相同配置,并且和低优先级形成互补配置. –file:./config/ ###根目录config目录下 –fi ...

  5. SpringBoot静态资源配置访问上传文件

    使用SpringBoot项目开发上传文件的代码时,如果想访问已上传的文件,但处于测试阶段,而不想配置Nginx服务并启动这么繁琐,那么配置以下代码即可 @Override public void ad ...

  6. Myql 中的事务回滚机制概述 ?

    事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个 不可分割的工作单位,事务回滚是指将该事务已经完成的对数据库的更新操作撤 销.要同时修改数据库中两个不同表时,如果它们不是一个事务 ...

  7. Djnago中缓存配置(redis配置案例)

    Django中提供了6种缓存方式: 开发调试 内存 文件 数据库 Memcache缓存(python-memcached模块) Memcache缓存(pylibmc模块) 配置文件 # 内存 CACH ...

  8. 学习ITIL

    ITIL IT运维管理体系: IT管理中的PPT(people人:process流程:technology技术): 标准化(是否有紧急故障处理流程).工具化: 备份解决方案:灾备解决方案: 监控解决方 ...

  9. 学习 Haproxy (五)

    1 Linux Haproxy 负载均衡 v1.8 ★★★ 类似于ningx的反向代理1.1 Haproxy 概述 Haproxy是一个开源的高性能的反向代理或者说是负载均衡服务软件之一,它支持双机热 ...

  10. nRF Connect SDK(NCS)/Zephyr固件升级详解 – 重点讲述MCUboot和蓝牙空中升级

    如何在nRF Connect SDK(NCS)中实现蓝牙空中升级?MCUboot和B0两个Bootloader有什么区别?MCUboot升级使用的image格式是怎么样的?什么是SMP协议?CBOR编 ...