How to create a Java Map<String,String> with unmodifiable keys? -


in java, how should create map<string,string> has unmodifiable keys, while keeping values modifiable.

i'd hand map<string,string> through interface else add/change map values, not able change map keys.

the background on higher level problem have list/set of variable names (with tree structure) (represented java string) i'd code on other side of java interface able populate aliases (also strings) each of variable names. i'd have multiple implementations of interface naming tree hierarchy can aliases different ways fit different situations. having interface implementation populate map<string,string> bunch of keys set-in-stone (and maybe containing defaults values) , allowing modify values (but not keys), seems best approach. i'm creating mapping between names , alias, map<> makes sense.

back lower level problem. i'd code resemble:

    public class myclass     {         public interface imymapper         {             void build(map<string,string> mapping);         }          imymapper mapper;          // how i'd use         void work()         {             map<string,string> map ;             // magic collections unmodifiablemap, keys             // maybe question should how magic unmodifiablemap works, reproduce it??             mapper.build(map);              // because maps<> reference, changed made (to values) reflected here         }     }      public class theirclass implements myclass.imymapper     {         @override         public void build(map<string,string> mapping)         {             // use mapping map<string,string> without extra/foreign classes             // not able modify map keys             // able change map values             // should able use of awesome map stuff, foreach, values, compute         }     } 

i know there collections unmodifiablemap(map<> m) makes values unmodifiable. if values mutable objects, modify them i'd stick strings (avoiding creating class set/get single string member, or creating structure-like-class public string member).

aka, i'd avoid creating own mutable class-values, , use collections unmodifiablemap() make keys , value references unmodifiable:

    // mutable reference string     public class extraworkforforeveryone     {         public string value;          public void setvalue(string value) { ... }         public string getvalue() { ... }     }      // , use:     void work()     {                     map<string,extraworkforeveryone> map;         map = collections.unmodifiablemap( ... );         // because collections.unmodifiablemap() stops them changing map references,         // interfacer still change extraworkforeveryone internals.         // not change keys refs or value refs, change value data.         mapper.build(map);          // because maps<> reference, changed made (to values) reflected here     } 

i extend or implement own map, (like how collections unmodifiablemap()) override methods change keys throw unsupportedoperationexception. java 8, there has been large number of methods added using lambda functions, nice interface implementers have access to, long not change keys.

aka, i'd avoid lengthy , error-prone technique:

    public final class finalhashmap extends hashmap     {         @override // might able change map keys         so_many_methods_and_edge_cases()         { throws unsupportedoperationexception }     } 

is there existing interface allows changing data of values of maps<>?

what other options creating resembling map<string,string> has unmodifiable keys, modifiable values? interested in coding practices, if possible.

seems you're looking proxy pattern.


detailed answer:

the idea use what's called proxy interact map. proxy intercept calls map; should able interact map through proxy. acts interface between client , map.

a proxy skeleton of "wrapping". since creating proxy map, proxy should implement map interface:

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 map } 

most methods telescope map. modify methods need prevent removing keys or adding new keys map, such put, putall , remove:

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 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 map!");             }         }          this.map.putall(map);     }      @override     public void clear() {         throw new unsupportedoperationexception("you cannot remove entries map!");     }      @override     public set<k> keyset() {         return collections.unmodifiableset(map.keyset());     }      @override     public collection<v> values() {         return collections.unmodifiableset(map.values()); //prevebt changing values null     }      @override     public set<map.entry<k, v>> entryset() {         //to allow modification of values, create own ("immutable") entry set , return         return collections.unmodifiableset(map.entryset());      } } 

keynotes:

  1. collections.unmodifiableset should used when returning sets map. ensures if person attempts modify set returned map, it'll throw unsupportedoperationexception

  2. creating new map containing values of map passed constructor prevents client modifying immutablemap using map passed it.


Popular posts from this blog