Перейти к основному содержимому

Реализации неизменяемых карт в Java

· 3 мин. чтения

1. Обзор

Иногда предпочтительнее запретить внесение изменений в java.util.Map , например совместное использование данных, доступных только для чтения, между потоками. Для этой цели мы можем использовать либо неизменяемую карту, либо неизменяемую карту.

В этом кратком руководстве мы увидим, в чем разница между ними. Затем мы представим различные способы создания неизменяемой карты.

2. Неизменяемый против неизменного

Немодифицируемая карта — это просто оболочка над модифицируемой картой, и она не позволяет изменять ее напрямую:

Map<String, String> mutableMap = new HashMap<>();
mutableMap.put("USA", "North America");

Map<String, String> unmodifiableMap = Collections.unmodifiableMap(mutableMap);
assertThrows(UnsupportedOperationException.class,
() -> unmodifiableMap.put("Canada", "North America"));

Но базовая изменяемая карта по-прежнему может быть изменена, и изменения также отражаются на немодифицируемой карте:

mutableMap.remove("USA");
assertFalse(unmodifiableMap.containsKey("USA"));

mutableMap.put("Mexico", "North America");
assertTrue(unmodifiableMap.containsKey("Mexico"));

Неизменяемая карта, с другой стороны, содержит свои собственные личные данные и не позволяет их модифицировать. Поэтому данные не могут каким-либо образом измениться после создания экземпляра неизменяемой карты.

3. Неизменная карта Гуавы

Guava предоставляет неизменяемые версии каждого java.util . Карта с использованием ImmutableMap . Он генерирует исключение UnsupportedOperationException всякий раз, когда мы пытаемся изменить его.

Поскольку он содержит свои собственные личные данные, эти данные не изменятся при изменении исходной карты.

Теперь мы обсудим различные способы создания экземпляров ImmutableMap.

3.1. Использование метода copyOf()

Во-первых, воспользуемся методом ImmutableMap.copyOf() , который возвращает копию всех записей, как в исходной карте:

ImmutableMap<String, String> immutableMap = ImmutableMap.copyOf(mutableMap);
assertTrue(immutableMap.containsKey("USA"));

Его нельзя изменить прямо или косвенно:

assertThrows(UnsupportedOperationException.class,
() -> immutableMap.put("Canada", "North America"));

mutableMap.remove("USA");
assertTrue(immutableMap.containsKey("USA"));

mutableMap.put("Mexico", "North America");
assertFalse(immutableMap.containsKey("Mexico"));

3.2. Использование метода строитель()

Мы также можем использовать метод ImmutableMap.builder() для создания копии всех записей, как на исходной карте.

Более того, мы можем использовать этот метод для добавления дополнительных записей, которых нет в исходной карте:

ImmutableMap<String, String> immutableMap = ImmutableMap.<String, String>builder()
.putAll(mutableMap)
.put("Costa Rica", "North America")
.build();
assertTrue(immutableMap.containsKey("USA"));
assertTrue(immutableMap.containsKey("Costa Rica"));

Как и в предыдущем примере, мы не можем изменить его прямо или косвенно:

assertThrows(UnsupportedOperationException.class,
() -> immutableMap.put("Canada", "North America"));

mutableMap.remove("USA");
assertTrue(immutableMap.containsKey("USA"));

mutableMap.put("Mexico", "North America");
assertFalse(immutableMap.containsKey("Mexico"));

3.3. Использование метода ()

Наконец, мы можем использовать метод ImmutableMap.of() для создания неизменяемой карты с набором записей, предоставляемых на лету. Он поддерживает не более пяти пар ключ/значение:

ImmutableMap<String, String> immutableMap
= ImmutableMap.of("USA", "North America", "Costa Rica", "North America");
assertTrue(immutableMap.containsKey("USA"));
assertTrue(immutableMap.containsKey("Costa Rica"));

Мы также не можем изменить его:

assertThrows(UnsupportedOperationException.class,
() -> immutableMap.put("Canada", "North America"));

4. Вывод

В этой быстрой статье мы обсудили различия между неизменяемой картой и неизменной картой.

Мы также рассмотрели различные способы создания ImmutableMap в Guava .

И, как всегда, полные примеры кода доступны на GitHub .