Streams与Collectors.toMap()两种实现方案对比及相关问题咨询
代码方案对比与合并函数结果疑问
方案对比:哪种更可取?
方案一
public Map<String, List<MyObj>> approach1( Iterable<? extends String> keys) { return StreamSupport.stream(keys.spliterator(), false) .map(dt -> new AbstractMap.SimpleEntry<>(dt, load(dt))) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, HashMap::new)); }
方案二
public Map<String, List<MyObj>> approach2( Iterable<? extends String> keys) { return StreamSupport.stream(keys.spliterator(), false) .collect(toMap(dt -> dt, k -> load(dt), (a, b) -> a, HashMap::new)); }
毫无疑问方案二更可取,理由如下:
- 更简洁直接:省去了中间创建
AbstractMap.SimpleEntry的冗余步骤,代码逻辑一目了然——直接将每个key映射为自身,对应值通过load(key)获取。 - 性能更优:减少了不必要的对象创建与销毁,避免了额外的内存开销。
- 可读性更高:没有多余的包装层,维护成本更低。
方案一中显式创建Map条目完全没有优势,属于画蛇添足的操作,只会增加代码复杂度和运行开销。
后续问题解答:重复key顺序不同时合并函数的结果
合并函数(a, b) -> a的结果是否一致,取决于load方法的特性:
- 如果
load是纯函数(相同输入始终返回相同结果,无副作用):不管重复key在Iterable中的顺序如何,最终Map中对应key的值都是一致的——因为多次调用load(key)返回的结果相同,合并时保留先处理的值也不会有差异。 - 如果
load存在副作用或非纯逻辑(比如每次调用返回新的对象实例、依赖外部状态变化等):结果会随重复key的处理顺序变化而不同。因为a代表先处理的key对应的load结果,b是后处理的,合并函数保留a,所以先出现的key对应的结果会被留在Map中,顺序不同就可能导致最终值不同。
另外需要注意:HashMap本身不保证键的顺序,但这不会影响合并函数的逻辑——合并逻辑只和重复key的处理先后顺序有关,和最终Map的存储顺序无关。
内容的提问来源于stack exchange,提问作者samshers
相关产品推荐
相关产品推荐

