Reputation: 1436
If I have a data structure which looks like this:
ImmutableObj<MutableMap<String,Integer>> myObj;
Is the above enough to ensure immunity? Or do I have to make MutableMap
immutable as well?
Upvotes: 1
Views: 78
Reputation: 1786
It's safe when you don't expose link to original mutable object like this (example with lists, same method for map is presents in Collections class):
List<String> strings = Arrays.asList("Foo", "Bar");
List<String> immutableStrings = Collections.unmodifiableList(strings);
because you may have to modify immutableStrings list through strings list. Better approach is to don't have links to mutable list at all like:
List<String> immutableStrings = Collections.unmodifiableList(Arrays.asList("Foo", "Bar"));
Here we don't have link to inner mutable list with foo and bar, and not able to modify immutableStrings list.
It's synthetic example, from conversation under your question i understand that you may want something like this:
public Map<String, Integer> wordFruquencyIn(String book, String word) {
//do calculation here
Map<String, Integer> result = //result
return Collections.unmodifiableMap(result); // return unmodifiable map
}
Better to create custom class that represents result of calculation instead of map, because contracts of Map, List, etc... unclear in way you don't know if they mutable or not (lack of method isMutable() and lack of design in early java versions in general (see LSP principle in this case)). After refactor you code may be like that:
public Statistics wordFruquencyIn(String book, String word) {
//do calculation here
Map<String, Integer> result = //result
return new StatisticsImpl(result);
}
public interface Statistics {
public String word() {}
public int times() {}
}
You may create any implementation of Statistics interface that fulfill contract of this interface and have map inside or any mutable data, only one way to communicate with this class is ask about word()
that returns already immutable string or times()
that returns a primitive.
Upvotes: 1