当前位置: 首页 > 知识库问答 >
问题:

如何使用不可修改的键创建Java映射?

扈运浩
2023-03-14

在java中,如何创建映射

我想把这张地图递给你

较高级别问题的背景是,我有变量名的列表/集合(具有树状结构)(表示为java String),我希望java接口另一侧的代码能够为每个变量填充别名(也是Strings)变量名。我希望有这个接口的多种实现,这样命名树层次结构可以是别名,以适应不同的情况。让接口实现填充Map

回到下层问题。我希望我的代码类似于:

    public class MyClass
    {
        public interface IMyMapper
        {
            void build(Map<String,String> mapping);
        }

        IMyMapper mapper;

        // How I'd like to use it
        void work()
        {
            Map<String,String> map ;
            // Magic something like Collections unmodifiableMap, but only for keys
            // Maybe my question should be how this magic for UnmodifiableMap works, so I could reproduce it??
            mapper.build(map); 
            // Because Maps<> are by reference, changed they made (to the values) would be reflected here
        }
    }

    public class TheirClass implements MyClass.IMyMapper
    {
        @Override
        public void build(Map<String,String> mapping)
        {
            // use mapping like Map<String,String> without extra/foreign classes
            // but not be able to modify the Map keys
            // only be able to change the Map values
            // Should be able to use all of the awesome Map stuff, like foreach, values, compute
        }
    }

我知道有集合不可修改Map(Map

又名,我想避免创建我自己的可变类值,并使用集合不可修改映射()使键和值引用不可修改:

    // mutable reference to a String
    public class ExtraWorkForForEveryone
    {
        public String value;

        public void setValue(String value) { ... }
        public String getValue() { ... }
    }

    // and then use:
    void work()
    {            
        Map<String,ExtraWorkForEveryone> map;
        map = Collections.unmodifiableMap( ... );
        // because Collections.unmodifiableMap() only stops them from changing the Map references,
        // the interfacer could still change the ExtraWorkForEveryone internals.
        // so they could not change keys refs or value refs, but they could change value data.
        mapper.build(map); 
        // Because Maps<> are by reference, changed they made (to the values) would be reflected here
    }

我可以扩展或实现我自己的映射,然后(比如如何Collections unmodifiableMap())覆盖所有可能更改键的方法抛出UnsupportedOperationException。但是在Java8中,有大量使用Lambda函数添加的方法,只要接口实现者不能更改密钥,就可以访问这些方法。

AKA,我想避免这种冗长且容易出错的技术:

    public final class FinalHashMap extends HashMap
    {
        @Override // anything that might be able to change the Map Keys
        so_many_methods_and_edge_cases()
        { throws UnsupportedOperationException }
    }

是否存在只允许更改映射值数据的现有接口

创建类似于Map的东西的其他选项是什么?


共有2个答案

江丰羽
2023-03-14

您可能需要限制地图的大小

你可以用你的看跌方法

if (map.size() == maxEntries) {
             throw some exception;
席兴平
2023-03-14

看起来你在寻找代理模式。

详细回答:

其思想是使用所谓的代理与地图交互。代理将拦截对映射的所有调用;您应该只能通过代理与地图交互。它充当客户端和映射之间的接口。

代理是您正在“包装”的内容的骨架。由于您正在为地图创建代理,因此代理应实现map界面:

class ImmutableMap<K, V> implements Map<K, V> {
    private Map<K, V> map;

    public ImmutableMap(Map<K, V> map) {
        this.map = new HashMap<>(map); // detach reference
    }

    //implement methods from Map
}

大多数方法只需伸缩到地图。修改所需的方法以防止删除键或向地图添加新键,例如putputAllremove

final class ImmutableMap<K, V> implementsMap<K, V> {
    private Map<K, V> map;

    public ImmutableMap(Map<K, V> map) {
        this.map = new HashMap<>(map);
    }

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

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return map.containsValue(value);
    }

    @Override
    public V get(Object key) {
        return map.get(key);
    }

    @Override
    public V put(K key, V value) {
        if(!map.containsKey(key)) {
            throw new IllegalArgumentException("Cannot add new keys!");
        }

        return map.put(key, value);
    }

    @Override
    public V remove(Object key) {
        throw new UnsupportedOperationException("You cannot remove entries from this map!");
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map) {
        for(K key : map.keySet()) {
            if(!this.map.containsKey(key)) {
                throw new IllegalArgumentException("Cannot add new keys to this map!");
            }
        }

        this.map.putAll(map);
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("You cannot remove entries from this map!");
    }

    @Override
    public Set<K> keySet() {
        return Collections.unmodifiableSet(map.keySet());
    }

    @Override
    public Collection<V> values() {
        return Collections.unmodifiableSet(map.values()); //prevebt changing values to null
    }

    @Override
    public Set<Map.Entry<K, V>> entrySet() {
        //to allow modification of values, create your own ("immutable") entry set and return that
        return Collections.unmodifiableSet(map.entrySet()); 
    }
}

基调:

>

  • 集合。从地图返回集合时,应使用unmodifiableSet。这确保了如果一个人试图修改从映射返回的集合,它将抛出一个UnsupportedOperationException

    创建一个新的映射,其中包含传递到构造函数中的映射的值,可防止客户端使用传递到构造函数中的映射修改不可变映射

  •  类似资料:
    • 我即将掌握新的Java8流和lambda选项,但仍有一些微妙之处我还没有完全理解。 假设我有一张地图,上面的键是人名。每个名字的值都是年龄和实例的映射。进一步假设不存在多个具有相同姓名和年龄的人。 在填充该地图(其他地方)后,我想为每个名字生成另一张最年长者的地图。我想得到一张

    • 问题内容: 我尝试了上面的代码,看是否可以重新分配最终数组的变量[ ans :it可以是]。我知道,通过最终Integer []数组,这意味着我们无法分配除拥有的Integer []之外的另一个实例。我想知道是否有可能使数组变量也不能修改。 问题答案: 据我所知这是不可能的。 但是,有一个Collections.unmodifiableList(..)方法可创建例如的不可修改视图。 如果要保证甚至

    • 问题内容: 我想要初始化a,并希望始终从流外部输入相同的值。 但是Java抱怨如下: 收集器类型中的toMap(Function,Function)方法不适用于参数(Function,BigDecimal) 为什么不能从外部使用BigDecimal?如果我写: 它会起作用,但这当然不是我想要的。 问题答案: 的第二个参数(如第一个参数)是一个函数,它接受流元素并返回映射的值。 在这种情况下,您想忽

    • 我有一个我搜索的对象,该对象存储在一个流中。我想让用户能够修改现有流中的元素,并用修改后的元素更新现有列表,而不是创建一个新的列表。这个问题与这个问题相似,只是用户正在将修改后的元素添加到一个新的列表中 项目类别

    • 问题内容: 在此代码中,如何为组合键生成Java类(如何在hibernate状态下组合键): 问题答案: 要映射组合键,你可以使用EmbeddedId 或在IdClass注解。我知道这个问题不仅仅涉及JPA,但规范定义的规则也适用。因此,它们是: 2.1.4主键和实体身份 … 组合主键必须对应于单个持久性字段或属性,或对应于如下所述的一组此类字段或属性。必须定义一个主键类来表示一个复合主键。当数据

    • 问题内容: 我试图设置一个不可修改的。 在我的代码中,我有一个返回列表的方法。 此列表不应该修改,但我不想捕获unmodifiableList返回的异常。 它是现有代码,我必须对其进行转换以返回不可修改的列表,但是如果调用了“ add”方法,则不必捕获任何异常。 首先,我创建一个类,该类实现List来覆盖“ add”方法以记录异常而不是捕获异常。 但是我不知道如何正确地实例化它。 问题答案: 如果