Существует ли реализация Java Map, которая обеспечивает окончательные ключи?

Мне нужен Map, который после того, как ключ получит значение, любая дополнительная попытка поместить значение на один и тот же ключ вызовет исключение.

Например:

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

Конечно, я могу реализовать это самостоятельно (например, расширяя HashMap или окружая каждый вызов put с помощью if map.contains(key)), но я предпочитаю использовать что-то готовое, чтобы мой код был чистым.

Кто-нибудь знает о такой реализации?

Ответы

Ответ 1

В JDK такой реализации нет. Лучше всего здесь использовать композицию:

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
}

В противном случае, как предложили другие, если вы используете Guava, используйте ForwardingMap; это по существу обобщенная версия вышеуказанного кода.

На самом деле, используйте Guava.


другое примечание: вы не можете просто // throws some exception здесь; Map .put() не объявляет об отказе от каких-либо исключений, поэтому ваш единственный вариант заключается в том, чтобы исключить неконтролируемое исключение.

Ответ 2

ImmutableMap класс в библиотеках Google Java (Guava) - это решение, которое вы ищете. Вам нужны финальные ключи, которые означают, что значения на вашей карте также будут окончательными. И вы можете построить свою карту следующим образом:

ImmutableMap<String,Integer> myMap = ImmutableMap.<String, Integer>builder()
    .put("john", 3) 
    .put("rogerio", 5)
    .put("alfonso", 45)
    .put("leonidas", 577)
    .build();