aspose file tools*
The moose likes Beginning Java and the fly likes Create Immutable HashMap Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Create Immutable HashMap" Watch "Create Immutable HashMap" New topic
Author

Create Immutable HashMap

Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Hello - I have a situation where in I need to send a hashmap as an argument to another method. And I do not have any control over this other method and I have to make sure that the HashMap I am passing should not be updated.

I could have used Collections.unModifiableMap() to a get an unmodifiableMap but, the I need to specifically pass HashMap and not just any Map.

Please let me know how to achieve this.

Thanks!
M
Hunter McMillen
Ranch Hand

Joined: Mar 13, 2009
Posts: 492



takes a map as an argument and returns it in a context where it can't be modified. If you pass it a HashMap<K,V> it will still return a HashMap<K,V>:



Hope this helps.
Hunter


"If the facts don't fit the theory, get new facts" --Albert Einstein
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Hi - thanks for the reply.

But Collections.unModifiableMap() will always return an object of type Map. Return type does not depend on what type we are passing in.

See javadoc here http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#unmodifiableMap%28java.util.Map%29

Am I missing something? Is there any other approach ?
Hunter McMillen
Ranch Hand

Joined: Mar 13, 2009
Posts: 492

Map is just an interface, what will actually be returned is a concrete implementation of that interface; which in this case is a HashMap since that is what you are passing in to the method.

The nice thing about the unmodifiableMap(...) returning a Map instead of a HashMap is that if later down the road you decide you don't want to use a HashMap , but instead a HashTable or a TreeMap all of the code should still function the same.

Hunter
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Hunter - The return type is Map which is an interface and I am sure that concrete implementation would be returned by this method. However the concrete implementation returned will always be of type java.util.Collections$UnmodifiableMap

If we try out below code snippet we get ClassCastException



Without cast, we would get compilation error, with casting to HashMap, we get runtime exception saying Exception in thread "main" java.lang.ClassCastException: java.util.Collections$UnmodifiableMap cannot be cast to java.util.HashMap

Hunter McMillen
Ranch Hand

Joined: Mar 13, 2009
Posts: 492

You're right the left hand side of the statement will need to say Map<K,V> but this will work for any map implementation:




Hunter
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Thats correct. If on left hand side I use Map instead HashMap, it would work.

But I have to pass this unmodifiable hashmap to aother method whose signature looks like below



If I create a unmodifiable map like you said, I would end up with a Map i.e if I do



the above unmodifiableMap cannot be passed to my transform method as it is expecting specifically HashMap and not just any Map
Jesper de Jong
Java Cowboy
Saloon Keeper

Joined: Aug 16, 2005
Posts: 14143
    
  18

If the method that you have to call takes a HashMap instead of a Map, and you cannot change that method, then what you want is not possible.

Collections.unmodifiableMap wraps a map in a special Map implementation that throws an exception if you try to call any methods on it that modify the map. But it does not, and it cannot, return a java.util.HashMap.

What you can do is make a defensive copy of your HashMap and pass that to the method. Then, if the method modifies the copy, you will have your original HashMap.


Java Beginners FAQ - JavaRanch SCJP FAQ - The Java Tutorial - Java SE 7 API documentation
Scala Notes - My blog about Scala
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
hmm... thanks for the replies Hunter and Jasper..!
Jesper de Jong
Java Cowboy
Saloon Keeper

Joined: Aug 16, 2005
Posts: 14143
    
  18

I just thought of another possibility.

You could create your own class that extends HashMap. Implement all methods that modify the map to throw an exception, for example an UnsupportedOperationException. Then pass that map to the transform method. Since it's a subclass of HashMap, it will work.

Note that this is in principle possible, but you're really stretching and bending your code to make it work with the badly designed transform method. I'd only do something like this if there is really no other possibility.

(To do it right you should ofcourse also use generics).
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Yes, I thought of this approach too, but it is like doing too much just to obey to transform method's signature...
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7772
    
  21

Manjunath An wrote:Yes, I thought of this approach too, but it is like doing too much just to obey to transform method's signature...

Yes, because the method's signature is wrong. If it only 'transforms' HashMaps, it should say so in the name, and, to be honest, it strikes me as a very bad piece of design.

I'm with Jesper (his first post). Until you get this design error fixed, use:
transform(new HashMap(data));
and put up with the (probably small) performance hit.

Alternatively, set up your own transform(Map) method that simply forwards to the existing one exactly as above. The advantage of that is that when the author of that method eventually gets it right, you can just change it to a simple direct call.

Also, I strongly suggest that you (and the person that wrote the method) start using generics.

Winston


Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Thanks Winston!
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7772
    
  21

Manjunath An wrote:Thanks Winston!

You're welcome. Hope you saw the addition about using a forwarder; I think that's probably the approach I'd take.

"Every problem in computer science can be solved by a layer of indirection" - David Wheeler

Winston
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38756
    
  23
One warning about unmodifiable: it doesn’t mean the same as immutable. It returns a read-only view of the original Map. If you change the original Map, the unmodifiable version changes too.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Please BeForthrightWhenCrossPostingToOtherSites.(←click) It's rather frustrating to spend time trying to help someone, only to find they've already gotten their answer elsewhere.

https://forums.oracle.com/forums/thread.jspa?threadID=2361539&tstart=0
Pat Farrell
Rancher

Joined: Aug 11, 2007
Posts: 4655
    
    5

Use Google's free, open source Guava collections code. They have ImmutableMap, ImmutableList, ImmutableSet, etc.
Wonderful library.
Manjunath An
Greenhorn

Joined: Sep 22, 2009
Posts: 15
Hi all - Yes, I did post this topic elsewhere, in future would make sure to add a statement that "I posted this question the other day in SomeOtherForum.com [link], but wasn't able to get a good answer, so now I'm asking here..". Sorry about this and thanks again for all the replies.

Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 38756
    
  23
Apologies accepted.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Create Immutable HashMap