Kevin
Kevin

Reputation: 6831

How can we make a HashMap-typed parameter not editable?

Sorry my title may be misleading.

This is actually from one of my recent JAVA interviews, the interviewer asked me this question: if we have a parameter that is of type HashMap, how can we make sure that in the accepting method, there is no way the user can modify this HashMap (i.e., get() method)

I was saying using final during the interview, which the interviewer didn't appreciate at all, and I've searched online for this topic for a while still have no clue.

Could experts help? Thanks

Upvotes: 0

Views: 1520

Answers (7)

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136062

There are 2 ways

1) this.map = Collections.unmodifiableMap(map);

2) defensive copying: this.map = new HashMap(map);

Upvotes: 0

Boris Brodski
Boris Brodski

Reputation: 8715

Using of final doesn't prevent from calling methods on the reference. It only makes the reference itself unchangeable. So your answer was wrong.

My suggestion is to use generic (only for such interviews, not in programs!):

    Map<String, String> map = new HashMap< String, String >();
    map.put("a", "b"); // OK

    Map< ? extends String, ? extends String > mapRO = new HashMap< String, String >();
    mapRO.put("a", "b"); // Compile error
    String value = mapRO.get("a"); // OK

As you can see, hiding generic types with ? extends ... prevent "writing" methods (like put) to be called, because they usually need the type to be fully defined. But you can still call clear(), so it's rather very pool security concept.

Also you can use some wrapper, that would throw an exceptions on all "writing" method calls.

Upvotes: 1

Russell Zahniser
Russell Zahniser

Reputation: 16364

It sounds like you may be coming from a C++ background, where making the parameter const would indeed prevent the method from modifying the object. In Java, final only prevents assigning to that variable; you can still call methods that modify the object itself.

So, for example:

void callingMethod() {
   HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
   map.put(1, 2);

   badMethod(map);

   // NullPointerException
   System.out.println(map.get(1).intValue());
}

void badMethod(final HashMap<Integer, Integer> map) {
   map.clear();
}

There are several ways to prevent this:

  1. Make a defensive copy before calling the method
  2. Wrap the object in an unmodifiable wrapper using Collections
  3. Use an explicitly immutable type such as those provided by Guava

Upvotes: 1

tilpner
tilpner

Reputation: 4338

How about creating an unmodifiable Collection from that Hashmap like here?

You would then do: yourMethod(Collections.unmodifiableMap(yourHashmap)); Using final only means that you wont be able to overwrite that reference with another reference in this block, it does not prevent any method calls on that object.

Upvotes: 0

G.S
G.S

Reputation: 10881

Collections.unmodifiableMap(myMap) will return the read-only map. You should work on the Map object returned by this.

Upvotes: 0

shyam
shyam

Reputation: 9368

Wrap the map you are passing using the Collections.unmodifiableMap

Upvotes: 0

Subhrajyoti Majumder
Subhrajyoti Majumder

Reputation: 41230

I think that is immutable or unmodifiable map.

Collections#unmodifiableCollection

It returns an unmodifiable view of the specified map. This method allows modules to provide users with "read-only" access to internal maps. Query operations on the returned map "read through" to the specified map, and attempts to modify the returned map, whether direct or via its collection views, result in an UnsupportedOperationException.

Reference

Upvotes: 0

Related Questions