In java, how should I create a Map<String,String>
that has unmodifiable keys, while keeping the values modifiable.
I'd like to hand this Map<String,String>
through an interface for someone else to add/change the Map values, but not be able to change the Map keys.
The background on higher level problem is that I have list/set of variable names (with tree like structure) (represented as java String) that I'd like code on the other side of the java interface to be able to populate aliases (also Strings) for each of the variable names. I'd like to have multiple implementations of this interface so naming tree hierarchy can be aliases different ways to fit different situations. Having the interface implementation populate a Map<String,String>
with bunch of keys already set-in-stone (and maybe containing defaults for the values) and allowing it to modify the values (but not the keys), seems like the best approach. I'm creating a mapping between names and alias, so Map<>
makes sense.
Back to the lower level problem. I'd like my code to resemble:
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
}
}
I know there is Collections unmodifiableMap(Map<> m)
but that also makes the values unmodifiable. If my values were mutable objects, then I could modify them but I'd like to stick with Strings
(avoiding creating Class with set/get for single String member, or creating Structure-like-class with public String member).
AKA, I'd like to avoid creating my own mutable class-values, and use Collections unmodifiableMap()
to make the keys and value references
unmodifiable:
// 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
}
I could extend or implement my own Map, then (like how Collections unmodifiableMap()
) override all methods that could change the keys throw UnsupportedOperationException
. But with Java 8, there has been a large number of methods added using Lambda functions, which would be nice for Interface implementers to have access to, as long as they could not change the keys.
AKA, I'd like to avoid this lengthy and error-prone technique:
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 }
}
Is there existing interface that only allows changing the data of values of Maps<>
?
What are my other options for creating something resembling a Map<String,String>
that has unmodifiable keys, but modifiable values? I am interested in good coding practices, if possible.