1. Обзор
В этом руководстве мы обсудим, как использовать встроенные классы Java, сторонние библиотеки и нашу пользовательскую реализацию для создания объекта Entry
, представляющего ассоциацию ключ-значение в Map
.
2. Использование встроенных классов Java
Java предоставляет Map
. Интерфейс Entry
с двумя простыми реализациями для создания Entry
. Давайте посмотрим на них.
2.1. Использование Абстрактной карты
. Простой ввод
Класс SimpleEntry
является статическим вложенным классом в классе AbstractMap
. Он предоставляет два разных конструктора для инициализации экземпляра:
AbstractMap.SimpleEntry<String, String> firstEntry = new AbstractMap.SimpleEntry<>("key1", "value1");
AbstractMap.SimpleEntry<String, String> secondEntry = new AbstractMap.SimpleEntry<>("key2", "value2");
AbstractMap.SimpleEntry<String, String> thirdEntry = new AbstractMap.SimpleEntry<>(firstEntry);
thirdEntry.setValue("a different value");
assertThat(Stream.of(firstEntry, secondEntry, thirdEntry))
.extracting("key", "value")
.containsExactly(
tuple("key1", "value1"),
tuple("key2", "value2"),
tuple("key1", "a different value"));
Как мы видим здесь, один из конструкторов принимает ключ и значение, а другой принимает экземпляр Entry
для инициализации нового экземпляра Entry .
2.2. Использование Абстрактной карты
. SimpleImmutableEntry
Как и в случае с SimpleEntry
, мы можем использовать SimpleImmutableEntry
для создания записей:
AbstractMap.SimpleImmutableEntry<String, String> firstEntry = new AbstractMap.SimpleImmutableEntry<>("key1", "value1");
AbstractMap.SimpleImmutableEntry<String, String> secondEntry = new AbstractMap.SimpleImmutableEntry<>("key2", "value2");
AbstractMap.SimpleImmutableEntry<String, String> thirdEntry = new AbstractMap.SimpleImmutableEntry<>(firstEntry);
assertThat(Stream.of(firstEntry, secondEntry, thirdEntry))
.extracting("key", "value")
.containsExactly(
tuple("key1", "value1"),
tuple("key2", "value2"),
tuple("key1", "value1"));
В отличие от SimpleEntry
, SimpleImmutableEntry
не позволяет нам изменять значение после инициализации экземпляра Entry .
Если мы попытаемся изменить значение, будет выброшено исключение java.lang.UnsupportedOperationException.
2.3. Использование карты
. вход
Начиная с версии 9, Java имеет статический метод entry()
в интерфейсе Map
для создания Entry
:
Map.Entry<String, String> entry = Map.entry("key", "value");
assertThat(entry.getKey()).isEqualTo("key");
assertThat(entry.getValue()).isEqualTo("value");
Мы должны иметь в виду, что запись, созданная таким образом, также является неизменной и приведет к исключению java.lang.UnsupportedOperationException
, если мы попытаемся изменить значение после инициализации.
3. Сторонние библиотеки
Помимо самой Java, есть несколько популярных библиотек, предоставляющих удобные способы создания записей.
3.1. Использование библиотеки Apache commons-collections4
Давайте начнем с включения нашей зависимости Maven :
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
Следует отметить, что помимо интерфейса Entry
, библиотека также предоставляет интерфейс под названием KeyValue:
Map.Entry<String, String> firstEntry = new DefaultMapEntry<>("key1", "value1");
KeyValue<String, String> secondEntry = new DefaultMapEntry<>("key2", "value2");
KeyValue<String, String> thirdEntry = new DefaultMapEntry<>(firstEntry);
KeyValue<String, String> fourthEntry = new DefaultMapEntry<>(secondEntry);
firstEntry.setValue("a different value");
assertThat(firstEntry)
.extracting("key", "value")
.containsExactly("key1", "a different value");
assertThat(Stream.of(secondEntry, thirdEntry, fourthEntry))
.extracting("key", "value")
.containsExactly(
tuple("key2", "value2"),
tuple("key1", "value1"),
tuple("key2", "value2"));
Класс DefaultMapEntry
предоставляет три разных конструктора. В то время как первый принимает пару ключ-значение, второй и третий принимают тип параметра Entry
и KeyValue
соответственно.
Точно так же ведет себя и класс UnmodifiedMapEntry
:
Map.Entry<String, String> firstEntry = new UnmodifiableMapEntry<>("key1", "value1");
KeyValue<String, String> secondEntry = new UnmodifiableMapEntry<>("key2", "value2");
KeyValue<String, String> thirdEntry = new UnmodifiableMapEntry<>(firstEntry);
KeyValue<String, String> fourthEntry = new UnmodifiableMapEntry<>(secondEntry);
assertThat(firstEntry)
.extracting("key", "value")
.containsExactly("key1", "value1");
assertThat(Stream.of(secondEntry, thirdEntry, fourthEntry))
.extracting("key", "value")
.containsExactly(
tuple("key2", "value2"),
tuple("key1", "value1"),
tuple("key2", "value2"));
Однако, как мы можем понять из названия, UnmodifiedMapEntry
также не позволяет нам изменять значение после инициализации .
3.2. Использование библиотеки Google Guava
Давайте сначала включим нашу зависимость Maven :
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
Теперь давайте посмотрим, как мы можем использовать метод immutableEntry()
:
Map.Entry<String, String> firstEntry = Maps.immutableEntry("key1", "value1");
Map.Entry<String, String> secondEntry = Maps.immutableEntry("key2", "value2");
assertThat(Stream.of(firstEntry, secondEntry))
.extracting("key", "value")
.containsExactly(
tuple("key1", "value1"),
tuple("key2", "value2"));
Поскольку он создает неизменяемую запись, если мы попытаемся изменить значение, он выдаст исключение java.lang.UnsupportedOperationException.
4. Пользовательская реализация
До сих пор мы видели несколько вариантов создания экземпляра Entry
для представления ассоциации ключ-значение. Эти классы разработаны таким образом, что они должны соответствовать внутренней логике реализаций интерфейса Map , таких как
HashMap
.
Это означает, что пока мы соблюдаем их, мы можем создать собственную реализацию интерфейса Entry .
Во-первых, давайте добавим простую реализацию:
public class SimpleCustomKeyValue<K, V> implements Map.Entry<K, V> {
private final K key;
private V value;
public SimpleCustomKeyValue(K key, V value) {
this.key = key;
this.value = value;
}
// standard getters and setters
// standard equals and hashcode
// standard toString
}
Наконец, давайте посмотрим на несколько примеров использования:
Map.Entry<String, String> firstEntry = new SimpleCustomKeyValue<>("key1", "value1");
Map.Entry<String, String> secondEntry = new SimpleCustomKeyValue<>("key2", "value2");
secondEntry.setValue("different value");
Map<String, String> map = Map.ofEntries(firstEntry, secondEntry);
assertThat(map)
.isEqualTo(ImmutableMap.<String, String>builder()
.put("key1", "value1")
.put("key2", "different value")
.build());
5. Вывод
В этой статье мы узнали, как можно использовать существующие параметры, предоставляемые Java, и несколько альтернатив, предоставляемых некоторыми популярными сторонними библиотеками для создания экземпляра Entry .
Кроме того, мы также создали пользовательскую реализацию и показали несколько примеров использования.
Как всегда, код этих примеров доступен на GitHub .