405

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?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Spiderman
  • 9,602
  • 13
  • 48
  • 56

11 Answers11

964

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:

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.

Dave L.
  • 43,907
  • 11
  • 63
  • 62
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • The above line returns compilation error for me (I am using java 5, BTW) - error message is: 'The type AbstractMap.SimpleEntry is not visible' – Spiderman Jun 24 '10 at 14:01
  • 7
    That's because `AbstractMap.SimpleEntry` wasn't public until Java 6, as you can see in the documentation. – Jesper Jun 24 '10 at 14:02
  • OK, so to summarise the short discussion - there is no out-of-the-box solution to it in Java 5 - I should use my own implementation to it. – Spiderman Jun 24 '10 at 14:06
  • 5
    +1 for pointing out `AbstractMap.SimpleEntry`. I guess you learn something new every day! – Priidu Neemre May 10 '13 at 15:20
  • 1
    what do you mean by enclosing in "an enclosing AbstractMap instance ". Is Enclosing inferring a technical term or something in java? please guide me. – C graphics Apr 29 '14 at 17:31
  • guava Maps.immutableEntry is what i was looking for – kommradHomer Aug 04 '15 at 12:46
  • @Jesper - Its great that we can create an Entry. But there is no easy way to add an entry to a map. Refer - https://stackoverflow.com/questions/39441096/how-to-put-an-entry-into-a-map ? I don't want to keep extracting data from the Entry and then put it into a map. I want the map to do the extraction for me. – MasterJoe Jul 26 '20 at 19:31
  • This Java release cadence has its headaches. 75% of the solutions on Stack Overflow don't work in my product! – Sridhar Sarnobat Aug 29 '22 at 21:27
200

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, ...).

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • It looks like Java provides basic features like this well after other languages do. Until then, we have to use clunky methods like this https://stackoverflow.com/a/3110563/6648326. – MasterJoe Jul 26 '20 at 19:25
  • 1
    Its great that we can create an Entry. But there is no easy way to add an entry to a map. Refer - https://stackoverflow.com/questions/39441096/how-to-put-an-entry-into-a-map ? I don't want to keep extracting data from the Entry and then put it into a map. I want the map to do the extraction for me. – MasterJoe Jul 26 '20 at 19:31
  • @MasterJoe you can just use `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())` – Valerij Dobler Apr 19 '21 at 15:27
84

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());
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 1
    Can you please explain why some implementations of Map has key as final (like in HashMap,ConcurrentHashMap), but not in some other implemementations like TreeMap,WeakHashMap? – AKS Aug 29 '13 at 17:26
  • 13
    The given code is not fully correct since it doesn't override equals and hashCode too which is required by interface Map.Entry – John Tang Boyland Nov 14 '14 at 01:28
  • As of Java 7 Update 80, I have implemented above and it worked ([pastebin](http://pastebin.com/ECCcd6R6)). No other methods were overridden. – k_rollo Sep 20 '15 at 02:11
  • 3
    @silver, only because seems to be working in some scenario, doesn't mean that is right. in a hash algorithm for instance, proper equais() and hashCode() implementations are used by consistency and performance. On a HashMap we are talking about performance and efficiency. On a TreeMap, can even drive to bugs. – Renascienza Aug 05 '21 at 04:24
  • @Rena If you need it, implement it. If you don't. Then don't. Simple. – k_rollo Sep 23 '21 at 01:51
57

Try Maps.immutableEntry from Guava

This has the advantage of being compatible with Java 5 (unlike AbstractMap.SimpleEntry which requires Java 6.)

Chris Frederick
  • 5,482
  • 3
  • 36
  • 44
finnw
  • 47,861
  • 24
  • 143
  • 221
36

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.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
20

You could actually go with: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

  • It's useful. https://github.com/google/guava Guava is a set of core Java libraries from Google that includes new collection types (such as multimap and multiset), immutable collections, a graph library, and utilities for concurrency, I/O, hashing, caching, primitives, strings, and more! It is widely used on most Java projects within Google, and widely used by many other companies as well. – Languoguang May 29 '20 at 03:08
18

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());
    }
}
velocity
  • 1,630
  • 21
  • 24
13

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

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
tanghao
  • 139
  • 1
  • 2
9

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.

parxier
  • 3,811
  • 5
  • 42
  • 54
4

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);
    }

}
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
Nels Beckman
  • 20,508
  • 3
  • 24
  • 28
  • 1
    Sorry, I posted this before reading all of the other comments. Looks like you want something that's included in the standard lib... – Nels Beckman Jun 24 '10 at 14:11
  • 3
    Google Guava makes a good point of why `Pair` implementations are a bad thing. [Source](https://groups.google.com/forum/#!topic/guava-discuss/GF4QyBu0gsI) – Ingo Bürk Apr 27 '14 at 09:35
3

If you are using Clojure, you have another option:

(defn map-entry
  [k v]
  (clojure.lang.MapEntry/create k v))
Resigned June 2023
  • 4,638
  • 3
  • 38
  • 49