概述
本教程将讨论如何使用Java内置类、第三方库以及自定义实现创建一个表示Map(/java-map-entry)中键值关联的Entry
对象。
2. 使用Java内置类
Java为Map
提供了两个简单的Entry
接口实现,让我们来了解一下。
2.1. 使用AbstractMap.SimpleEntry
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. 使用AbstractMap.SimpleImmutableEntry
与SimpleEntry
类似,我们可以使用SimpleImmutableEntry
创建Entry
:
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. 使用Map.entry()
从Java 9版本开始,Map
接口有一个静态方法entry()
用于创建Entry
:
Map.Entry<String, String> entry = Map.entry("key", "value");
assertThat(entry.getKey()).isEqualTo("key");
assertThat(entry.getValue()).isEqualTo("value");
需要注意的是,通过这种方式创建的Entry
也是不可变的,如果在初始化后尝试更改值,也会抛出java.lang.UnsupportedOperationException
。
3. 第三方库
除了Java本身,还有一些流行库提供了创建Entry
的便捷方式。
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
类型的参数。
UnmodifiableMapEntry
类的行为与此相同:
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"));
然而,从其名称可以理解,UnmodifiableMapEntry
也不允许在初始化后更改值。**
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"));
由于它创建了不可变的Entry
,如果尝试更改值,它会抛出java.lang.UnsupportedOperationException
。
4. 自定义实现
到目前为止,我们已经看到了几种创建Entry
实例的方法,表示键值关联。这些类的设计方式确保它们遵循Map
接口实现(如HashMap
/ java-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上找到。