Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Java Map implementation that enforces final keys?

Tags:

java

map

I need a Map, that once a key gets a value, any additional attempt of putting a value on the same key will throw an exception.

For example:

map.put("John", 3); //OK
map.put("John", 7); // throws some exception
map.put("John", 11); // throws some exception

Of course I can implement this on my own (e.g. by extending HashMap, or surrounding every call to put with if map.contains(key)), but I prefer using something ready-made that keeps my code clean.

Does anybody know of such implementation?

like image 814
OferBr Avatar asked Jun 02 '14 08:06

OferBr


2 Answers

There is no such implementation in the JDK. Your best bet here is to use composition:

public final class CustomMap<K, V>
    implements Map<K, V>
{
    private final Map<K, V> delegate;

    public CustomMap(final Map<K, V> delegate)
    {
        this.delegate = delegate;
    }

    @Override
    public V put(final K key, final V value)
    {
        // Can't use the return value of delegate.put(), since some implementations
        // allow null values; so checking delegate.put() == null doesn't work
        if (delegate.containsKey(key))
            throw new IllegalArgumentException("duplicate key: " + key);
        return delegate.put(key, value);
    }

    @Override
    public void putAll(@Nonnull final Map<? extends K, ? extends V> m)
    {
        for (final Entry<? extends K, ? extends V> entry: m.entrySet())
            put(entry.getKey(), entry.getValue());
    }

    // delegate all other methods
}

Otherwise, as others suggested, if you use Guava, use ForwardingMap; this is essentially a generalized version of the above code.

In fact, do use Guava.


other note: you can't just // throws some exception here; Map's .put() doesn't declare to throw any exception, so your only option is to throw an unchecked exception here.

like image 200
fge Avatar answered Oct 04 '22 02:10

fge


ImmutableMap class in Google Java libraries (Guava) is the solution you are looking for. You want final keys which implies that the values in your map will also be final-alike. And you can build your map like this:

ImmutableMap<String,Integer> myMap = ImmutableMap.<String, Integer>builder()
    .put("john", 3) 
    .put("rogerio", 5)
    .put("alfonso", 45)
    .put("leonidas", 577)
    .build();
like image 44
Juvanis Avatar answered Oct 04 '22 01:10

Juvanis