Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a hashmap of immutable generic objects

I don't think that there is a way that is efficient (if at all) of doing this, but I figured I'd ask in case someone else knows otherwise. I'm looking to create my own Cache/lookup table. To make it as useful as possible, I'd like it to be able to store generic objects. The problem with this approach is that even though you can make a Collections.unmodifiableMap, immutableMap, etc, these implementations only prevent you from changing the Map itself. They don't prevent you from getting the value from the map and modifying its underlying values. Essentially what I'd need is for something to the effect of HashMap<K, ? extends Immutable>, but to my knowledge nothing like this exists.

I had originally thought that I could just return a copy of the values in the cache in the get method, but since Java's Cloneable interface is jacked up, you cannot simple call

public V getItem(K key){
    return (V) map.get(k).clone();
}
like image 958
FuriousGeorge Avatar asked Dec 24 '13 21:12

FuriousGeorge


People also ask

How can we create immutable HashMap?

We used to use the unmodifiableMap() method of Collections class to create unmodifiable(immutable) Map. Map<String,String> map = new HashMap<String, String>(); Map<String,String> immutableMap = Collections. unmodifiableMap(map); Lets test this in JShell.

What is immutable HashMap?

ImmutableMap, as suggested by the name, is a type of Map which is immutable. It means that the content of the map are fixed or constant after declaration, that is, they are read-only. If any attempt made to add, delete and update elements in the Map, UnsupportedOperationException is thrown.

How do you declare a generic HashMap in Java?

Generic Map in simple language can be generalized as: Map< K, V > map = new HashMap< K, V >(); Where K and V are used to specify the generic type parameter passed in the declaration of a HashMap.


2 Answers

Your thinking is good, and you're right that there's no built-in way of handling immutability.

However, you could try this:

interface Copyable<T> {
    T getCopy();
}

Then override the get() method to return copies instead of the value itself;

class CopyMap<K, V extends Copyable<V>> extends HashMap<K, V> {
    @Override
    public V get(Object key) {
        return super.get(key).getCopy();
    }
}

Then it's up to the implementation to return a copy of itself, rather than this (unless the class itself is immutable). Although you can't enforce that in code, you would be within your rights to publicly humiliate the programmer that doesn't conform.

like image 156
Bohemian Avatar answered Sep 25 '22 23:09

Bohemian


I'm looking to create my own Cache/lookup table.

Why not use Guava's cache?

The problem with this approach is that even though you can make a Collections.unmodifiableMap, immutableMap, etc, these implementations only prevent you from changing the Map itself. They don't prevent you from getting the value from the map and modifying its underlying values.

This is not something any collection can enforce for you. You need to make the classes themselves immutable. There is a hacky approach using Reflection (which can also be used to make a class mutable!), but really, you should avoid this and simply create classes that are immutable.

like image 30
Amir Afghani Avatar answered Sep 23 '22 23:09

Amir Afghani