Java - So erstellen Sie einen neuen Eintrag (Schlüssel, Wert)

291

Ich mag neues Element erstellen , die in ähnlicher Weise zu , Util.Map.Entrydass die Struktur enthalten werden key, value.

Das Problem ist, dass ich a nicht instanziieren kann, Map.Entryweil es eine Schnittstelle ist.

Weiß jemand, wie man ein neues generisches Schlüssel- / Wertobjekt für Map.Entry erstellt?

Spider Man
quelle

Antworten:

79

Sie können die Map.Entry<K, V>Schnittstelle einfach selbst implementieren :

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

Und dann benutze es:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Jesper
quelle
117
Natürlich - ich habe mich nur gefragt, ob es dafür keine sofort einsatzbereite Lösung gibt. Ich versuche, meinen Code so standard wie möglich zu machen ...
Spiderman
1
Können Sie bitte erklären, warum einige Implementierungen von Map den Schlüssel als endgültig haben (wie in HashMap, ConcurrentHashMap), aber nicht in einigen anderen Implementierungen wie TreeMap, WeakHashMap?
AKS
7
Der angegebene Code ist nicht vollständig korrekt, da er nicht gleich und hashCode überschreibt, was von der Schnittstelle Map.Entry
John Tang Boyland
Ab Java 7 Update 80 habe ich oben implementiert und es hat funktioniert ( Pastebin ). Es wurden keine anderen Methoden überschrieben.
Silber
807

Es gibt public static class AbstractMap.SimpleEntry<K,V>. Lassen Sie sich nicht der AbstractTeil des Namens Sie täuschen: es ist in der Tat nicht eine abstractKlasse (aber in der obersten Ebene AbstractMapist).

Die Tatsache, dass es sich um eine staticverschachtelte Klasse handelt, bedeutet, dass Sie KEINE umschließende AbstractMapInstanz benötigen , um sie zu instanziieren. So etwas lässt sich also gut kompilieren:

Map.Entry<String,Integer> entry =
    new AbstractMap.SimpleEntry<String, Integer>("exmpleString", 42);

Wie in einer anderen Antwort erwähnt, verfügt Guava auch über eine praktische staticFactory-Methode Maps.immutableEntry, die Sie verwenden können.


Du sagtest:

Ich kann mich nicht Map.Entryselbst verwenden, da es anscheinend ein schreibgeschütztes Objekt ist, das ich nicht neu instanziieren kanninstanceof

Das ist nicht ganz richtig. Der Grund, warum Sie es nicht direkt instanziieren können (dh mit new), ist, dass es ein ist interface Map.Entry.


Vorbehalt und Trinkgeld

Wie in der Dokumentation angegeben, AbstractMap.SimpleEntrysteht @since 1.6es Ihnen also nicht zur Verfügung, wenn Sie sich an 5.0 halten.

Um nach einer anderen bekannten Klasse zu suchen, implements Map.Entrykönnen Sie tatsächlich direkt zum Javadoc gehen. Ab der Java 6 Version

Interface Map.Entry

Alle bekannten Implementierungsklassen :

Leider listet die Version 1.5 keine bekannte Implementierungsklasse auf, die Sie verwenden können, sodass Sie möglicherweise nicht in der Lage sind, Ihre eigene zu implementieren.

Polygenschmierstoffe
quelle
Die obige Zeile gibt einen Kompilierungsfehler für mich zurück (ich verwende Java 5, übrigens) - die Fehlermeldung lautet: 'Der Typ AbstractMap.SimpleEntry ist nicht sichtbar'
Spiderman
6
Das liegt daran, dass AbstractMap.SimpleEntryes bis Java 6 nicht öffentlich war, wie Sie in der Dokumentation sehen können.
Jesper
OK, um die kurze Diskussion zusammenzufassen: In Java 5 gibt es keine sofort einsatzbereite Lösung. Ich sollte meine eigene Implementierung verwenden.
Spiderman
4
+1 für den Hinweis AbstractMap.SimpleEntry. Ich denke du lernst jeden Tag etwas Neues!
Priidu Neemre
Was meinst du mit "einer einschließenden AbstractMap-Instanz"? Schliesst Enclosing auf einen Fachbegriff oder etwas in Java? Bitte führen Sie mich.
C Grafiken
70

Ab Java 9 gibt es eine neue Dienstprogrammmethode, mit der ein unveränderlicher Eintrag erstellt werden kann Map#entry(Object, Object).

Hier ist ein einfaches Beispiel:

Entry<String, String> entry = Map.entry("foo", "bar");

Da es unveränderlich ist, setValuewird ein Anruf ein werfen UnsupportedOperationException. Die anderen Einschränkungen sind die Tatsache, dass es nicht serialisierbar ist und nullals Schlüssel oder Wert verboten ist. Wenn es für Sie nicht akzeptabel ist, müssen Sie AbstractMap.SimpleImmutableEntryoder AbstractMap.SimpleEntrystattdessen verwenden.

NB: Wenn Sie direkt ein MapPaar mit 0 bis bis zu 10 (Schlüssel, Wert) Paaren erstellen möchten, können Sie stattdessen die Typmethoden verwenden Map.of(K key1, V value1, ...).

Nicolas Filotto
quelle
53

Versuchen Sie Maps.immutableEntry von Guava

Dies hat den Vorteil, dass es mit Java 5 kompatibel ist (im Gegensatz zu AbstractMap.SimpleEntryJava 6).

finnw
quelle
34

Beispiel für AbstractMap.SimpleEntry:

import java.util.Map; 
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;

Instanziieren:

ArrayList<Map.Entry<Integer, Integer>> arr = 
    new ArrayList<Map.Entry<Integer, Integer>>();

Zeilen hinzufügen:

arr.add(new AbstractMap.SimpleEntry(2, 3));
arr.add(new AbstractMap.SimpleEntry(20, 30));
arr.add(new AbstractMap.SimpleEntry(2, 4));

Zeilen abrufen:

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

Sollte drucken:

2
3
20
30
2
4

Es ist gut zum Definieren von Kanten von Diagrammstrukturen. Wie die zwischen Neuronen in deinem Kopf.

Eric Leschinski
quelle
18

Sie könnten tatsächlich gehen mit: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

Juan David Ortega Tapias
quelle
Es ist nützlich. github.com/google/guava Guava ist eine Reihe von Java-Kernbibliotheken von Google, die neue Sammlungstypen (wie Multimap und Multiset), unveränderliche Sammlungen, eine Diagrammbibliothek und Dienstprogramme für Parallelität, E / A, Hashing, Caching, Primitive, Strings und mehr! Es wird häufig in den meisten Java-Projekten innerhalb von Google und auch von vielen anderen Unternehmen verwendet.
Languoguang
13

Warum Map.Entry? Ich denke, so etwas wie ein Schlüssel-Wert-Paar ist für den Fall geeignet.

Verwenden Sie java.util.AbstractMap.SimpleImmutableEntryoderjava.util.AbstractMap.SimpleEntry

Tanghao
quelle
6

org.apache.commons.lang3.tuple.Pairimplementiert java.util.Map.Entryund kann auch eigenständig verwendet werden.

Auch wie andere erwähnt haben Guavas com.google.common.collect.Maps.immutableEntry(K, V)den Trick.

Ich bevorzuge Pairfür seine fließende Pair.of(L, R)Syntax.

Parxier
quelle
2
Darf ich ImmutablePairstattdessen vorschlagen ?
Beluchin
Ich mag die org.apache.commons.lang3.tuple.Pair-Klasse sehr, sie ist großartig!
Laurens Op 't Zandt
Das einzige, was ich daran nicht mag, ist, dass es nach links, rechts, Schlüssel, Wert serialisiert wird, wobei links = Schlüssel und rechts = Wert. Nur 2 zusätzliche nutzlose (möglicherweise) Werte in der serialisierten Zeichenfolge.
Vikrant Goel
4

Ich habe eine generische Pair-Klasse definiert, die ich ständig verwende. Es ist toll. Als Bonus muss ich durch die Definition einer statischen Factory-Methode (Pair.create) die Typargumente nur halb so oft schreiben.

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

}
Nels Beckman
quelle
1
Entschuldigung, ich habe dies gepostet, bevor ich alle anderen Kommentare gelesen habe. Sieht so aus, als ob Sie etwas wollen, das in der Standardbibliothek enthalten ist ...
Nels Beckman
2
Google Guava macht deutlich, warum PairImplementierungen eine schlechte Sache sind. Quelle
Ingo Bürk
3

Wenn Sie Clojure verwenden, haben Sie eine andere Option:

(defn map-entry
  [k v]
  (clojure.lang.MapEntry/create k v))
Radon Rosborough
quelle