You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效创建可增删改键值的HashMap视图,且不复制原Map?

基于Guava的轻量Map修改视图实现

核心思路

由于原Map(originalMap)生命周期内不会修改,且所有键值均为不可变类型,我们可以通过组合原Map与小型修改集创建视图,无需复制整个大Map:

  • 用小Map(overrides)存储新增/覆盖的键值对
  • 用集合(removals)存储需要删除的键

借助Guava的ForwardingMap代理所有Map方法,优先处理修改集逻辑,再回退到原Map,既保证语义正确,又避免全量复制的性能问题。

实现代码

import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.Map;
import java.util.Set;

public class ModifiedMapView<K, V> extends ForwardingMap<K, V> {
    private final Map<K, V> originalMap;
    private final Map<K, V> overrides;
    private final Set<K> removals;

    private ModifiedMapView(Map<K, V> originalMap, Map<K, V> overrides, Set<K> removals) {
        this.originalMap = originalMap;
        this.overrides = ImmutableMap.copyOf(overrides);
        this.removals = ImmutableSet.copyOf(removals);
    }

    public static <K, V> ModifiedMapView<K, V> create(
            Map<K, V> originalMap,
            Map<K, V> overrides,
            Set<K> removals) {
        return new ModifiedMapView<>(originalMap, overrides, removals);
    }

    @Override
    protected Map<K, V> delegate() {
        return originalMap;
    }

    @Override
    public V get(Object key) {
        if (overrides.containsKey(key)) {
            return overrides.get(key);
        }
        if (removals.contains(key)) {
            return null;
        }
        return originalMap.get(key);
    }

    @Override
    public boolean containsKey(Object key) {
        if (overrides.containsKey(key)) {
            return true;
        }
        if (removals.contains(key)) {
            return false;
        }
        return originalMap.containsKey(key);
    }

    @Override
    public Set<K> keySet() {
        return ImmutableSet.<K>builder()
                .addAll(originalMap.keySet())
                .addAll(overrides.keySet())
                .removeAll(removals)
                .build();
    }

    @Override
    public int size() {
        return keySet().size();
    }

    @Override
    public V put(K key, V value) {
        throw new UnsupportedOperationException("ModifiedMapView is immutable");
    }

    // 其他修改方法(putAll、remove、clear等)均抛出UnsupportedOperationException
}

使用示例

// 原10k+键值对的Map
Map<String, String> originalMap = ...;

// 定义修改规则:覆盖A为baz,新增C,删除B
Map<String, String> overrides = ImmutableMap.of("A", "baz", "C", "newValue");
Set<String> removals = ImmutableSet.of("B");

// 创建视图
Map<String, String> newMap = ModifiedMapView.create(originalMap, overrides, removals);

// 验证结果
newMap.get("A"); // 返回baz
newMap.containsKey("B"); // 返回false
newMap.get("C"); // 返回newValue
newMap.get("D"); // 返回原Map中D对应的值(若存在)

方案优势

  • 低内存消耗:仅复制小型修改集,原Map完全复用,避免10k+数据的重复存储
  • 高性能:所有方法的耗时仅取决于修改集大小,远低于全量复制的开销
  • 语义准确:重写了containsKey()、keySet()、size()等核心方法,完全符合Map接口规范
  • 不可变安全:视图本身实现为不可变,结合原Map和修改集的不可变性,避免意外修改

替代场景:原Map为Guava ImmutableMap时

如果原Map本身就是Guava的ImmutableMap,可以直接用ImmutableMap.builder实现增量构建,此时putAll是O(1)的视图复用,无需复制全量数据:

ImmutableMap<String, String> newMap = ImmutableMap.<String, String>builder()
        .putAll(originalMap)
        .put("A", "baz")
        .put("C", "newValue")
        .remove("B")
        .build();

但如果原Map是普通HashMap,这种方式仍会复制全量数据,性能不如ModifiedMapView。

内容的提问来源于stack exchange,提问作者rb612

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:01:29