如何高效判断嵌套Option对象组成的列表是否发生变更
判断深嵌套Option对象列表变更的最优方案
首先直接说明你最初的hashCode比对思路的本质缺陷:
靠hashCode判断对象变更无法做到准确可靠:主流编程语言的默认hashCode实现不会覆盖所有嵌套属性的计算,就算你手动给所有层级重写hashCode,一方面嵌套层级越深维护成本越高,漏写字段就会直接导致判断失效,另一方面存在哈希碰撞概率——两份不同内容的数据可能算出相同hash值,只能用来做快速初筛,不能当最终变更判断依据。
按落地成本和可靠性排序,可行方案如下:
- 首选方案:脏标记追踪(从修改源头感知变更)
给Option以及其所有嵌套的子属性类型实现属性变更通知能力,比如Java类内置PropertyChangeSupport工具、C#实现INotifyPropertyChanged接口、前端场景用Proxy代理属性读写,同时给列表本身的增删操作加拦截。只要任意层级的属性被修改、或是列表本身增删元素,就直接把全局的isChanged标记置为true,不需要事后做任何全量遍历比对。
这个方案性能最高,没有递归遍历开销,不管嵌套多深都能精准感知修改,是这类配置表单场景的标准实现思路。 - 次选方案:序列化快照比对(适配无法修改类源码的无侵入场景)
如果Option类是第三方依赖提供的,你没法修改类源码加变更通知,就在初始化时把列表用确定性序列化配置转成字符串/字节快照存下来,需要判断变更时,把当前状态的列表用完全相同的配置序列化,直接比对两个快照内容是否一致即可。
参考实现代码:
注意必须固定序列化规则,不能用字段输出顺序随机、默认值自动忽略的序列化配置,否则同一份数据两次序列化结果不同会产生误判。// 初始化阶段存原始快照 List<Option> optionList = GetOptionList(); ObjectMapper objectMapper = new ObjectMapper(); // 固定序列化规则:按固定顺序输出字段、不忽略任意字段、关闭格式化输出 objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); String originalSnapshot = objectMapper.writeValueAsString(optionList); // 操作完成后做比对 String currentSnapshot = objectMapper.writeValueAsString(optionList); boolean hasChanged = !originalSnapshot.equals(currentSnapshot); - 不推荐方案:递归遍历逐字段比对
不管是手动写递归Equals逻辑,还是用反射工具类做深比较,嵌套层级深的时候维护成本极高,后续Option类加新字段如果没同步更新比对逻辑就会漏判,列表数据量大的时候全量递归遍历的性能开销也很高。
内容的提问来源于stack exchange,提问作者trap
相关产品推荐
相关产品推荐

