I'd like to create new item that similarly to Util.Map.Entry
that will contain the structure key
, value
.
The problem is that I can't instantiate a Map.Entry
because it's an interface.
Does anyone know how to create a new generic key/value object for Map.Entry?
There's public static class AbstractMap.SimpleEntry<K,V>
. Don't let the Abstract
part of the name mislead you: it is in fact NOT an abstract
class (but its top-level AbstractMap
is).
The fact that it's a static
nested class means that you DON'T need an enclosing AbstractMap
instance to instantiate it, so something like this compiles fine:
Map.Entry<String,Integer> entry =
new AbstractMap.SimpleEntry<String, Integer>("exmpleString", 42);
As noted in another answer, Guava also has a convenient static
factory method Maps.immutableEntry
that you can use.
You said:
I can't use Map.Entry itself because apparently it's a read-only object that I can't instantiate new instanceof
That's not entirely accurate. The reason why you can't instantiate it directly (i.e. with new
) is because it's an interface Map.Entry
.
Caveat and tip
As noted in the documentation, AbstractMap.SimpleEntry
is @since 1.6
, so if you're stuck to 5.0, then it's not available to you.
To look for another known class that implements Map.Entry
, you can in fact go directly to the javadoc. From the Java 6 version
Interface Map.Entry All Known Implementing Classes: AbstractMap.SimpleEntry, AbstractMap.SimpleImmutableEntry
Unfortunately the 1.5 version does not list any known implementing class that you can use, so you may have be stuck with implementing your own.
Starting from Java 9, there is a new utility method allowing to create an immutable entry which is Map#entry(Object, Object)
.
Here is a simple example:
Entry<String, String> entry = Map.entry("foo", "bar");
As it is immutable, calling setValue
will throw an UnsupportedOperationException
. The other limitations are the fact that it is not serializable and null
as key or value is forbidden, if it is not acceptable for you, you will need to use AbstractMap.SimpleImmutableEntry
or AbstractMap.SimpleEntry
instead.
NB: If your need is to create directly a Map
with 0 to up to 10 (key, value) pairs, you can instead use the methods of type Map.of(K key1, V value1, ...)
.
Map.of("key1", "value1", "key2", "value2")
to add entries to a map. Or if you have an existing map: map.put(entry.getKey(), entry.getValue())
You can just implement the Map.Entry<K, V>
interface yourself:
import java.util.Map;
final class MyEntry<K, V> implements Map.Entry<K, V> {
private final K key;
private V value;
public MyEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V old = this.value;
this.value = value;
return old;
}
}
And then use it:
Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Try Maps.immutableEntry from Guava
This has the advantage of being compatible with Java 5 (unlike AbstractMap.SimpleEntry
which requires Java 6.)
Example of AbstractMap.SimpleEntry:
import java.util.Map;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
Instantiate:
ArrayList<Map.Entry<Integer, Integer>> arr =
new ArrayList<Map.Entry<Integer, Integer>>();
Add rows:
arr.add(new AbstractMap.SimpleEntry(2, 3));
arr.add(new AbstractMap.SimpleEntry(20, 30));
arr.add(new AbstractMap.SimpleEntry(2, 4));
Fetch rows:
System.out.println(arr.get(0).getKey());
System.out.println(arr.get(0).getValue());
System.out.println(arr.get(1).getKey());
System.out.println(arr.get(1).getValue());
System.out.println(arr.get(2).getKey());
System.out.println(arr.get(2).getValue());
Should print:
2
3
20
30
2
4
It's good for defining edges of graph structures. Like the ones between neurons in your head.
You could actually go with: Map.Entry<String, String> en= Maps.immutableEntry(key, value);
If you look at the documentation of Map.Entry you will find that it is a static interface (an interface which is defined inside the Map interface an can be accessed through Map.Entry) and it has two implementations
All Known Implementing Classes: AbstractMap.SimpleEntry, AbstractMap.SimpleImmutableEntry
The class AbstractMap.SimpleEntry provides 2 constructors:
Constructors and Description AbstractMap.SimpleEntry(K key, V value) Creates an entry representing a mapping from the specified key to the specified value. AbstractMap.SimpleEntry(Map.Entry extends K,? extends V> entry) Creates an entry representing the same mapping as the specified entry.
An example use case:
import java.util.Map;
import java.util.AbstractMap.SimpleEntry;
public class MyClass {
public static void main(String args[]) {
Map.Entry e = new SimpleEntry<String, String>("Hello","World");
System.out.println(e.getKey()+" "+e.getValue());
}
}
Why Map.Entry
? I guess something like a key-value pair is fit for the case.
Use java.util.AbstractMap.SimpleImmutableEntry
or java.util.AbstractMap.SimpleEntry
org.apache.commons.lang3.tuple.Pair
implements java.util.Map.Entry
and can also be used standalone.
Also as others mentioned Guava's com.google.common.collect.Maps.immutableEntry(K, V)
does the trick.
I prefer Pair
for its fluent Pair.of(L, R)
syntax.
ImmutablePair
instead?
I defined a generic Pair class that I use all the time. It's great. As a bonus, by defining a static factory method (Pair.create) I only have to write the type arguments half as often.
public class Pair<A, B> {
private A component1;
private B component2;
public Pair() {
super();
}
public Pair(A component1, B component2) {
this.component1 = component1;
this.component2 = component2;
}
public A fst() {
return component1;
}
public void setComponent1(A component1) {
this.component1 = component1;
}
public B snd() {
return component2;
}
public void setComponent2(B component2) {
this.component2 = component2;
}
@Override
public String toString() {
return "<" + component1 + "," + component2 + ">";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((component1 == null) ? 0 : component1.hashCode());
result = prime * result
+ ((component2 == null) ? 0 : component2.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Pair<?, ?> other = (Pair<?, ?>) obj;
if (component1 == null) {
if (other.component1 != null)
return false;
} else if (!component1.equals(other.component1))
return false;
if (component2 == null) {
if (other.component2 != null)
return false;
} else if (!component2.equals(other.component2))
return false;
return true;
}
public static <A, B> Pair<A, B> create(A component1, B component2) {
return new Pair<A, B>(component1, component2);
}
}
Pair
implementations are a bad thing. Source
If you are using Clojure, you have another option:
(defn map-entry
[k v]
(clojure.lang.MapEntry/create k v))
Success story sharing
AbstractMap.SimpleEntry
wasn't public until Java 6, as you can see in the documentation.AbstractMap.SimpleEntry
. I guess you learn something new every day!