1658 Stimmen

Wie initialisiere ich eine HashMap direkt (auf eine wörtliche Art und Weise)?

Gibt es eine Möglichkeit, eine Java HashMap so zu initialisieren?:

Map test = 
    new HashMap{"test":"test","test":"test"};

Was wäre die korrekte Syntax dafür? Ich habe dazu nichts gefunden. Ist das möglich? Ich suche nach dem kürzesten/schnellsten Weg, um einige "final/statische" Werte in eine Map einzufügen, die sich nie ändern und im Voraus bekannt sind, wenn die Map erstellt wird.

1 Stimmen

0 Stimmen

Eng verwandt: stackoverflow.com/questions/507602/… (Beide Fragen handeln davon, eine konstante Map mit statischen, finalen Werten zu initialisieren.)

0 Stimmen

2167voto

yankee Punkte 35636

Alle Versionen

Falls Sie nur einen einzelnen Eintrag benötigen: Es gibt Collections.singletonMap("key", "value").

Für Java Version 9 oder höher:

Ja, das ist jetzt möglich. In Java 9 wurden einige Factory-Methoden hinzugefügt, die die Erstellung von Maps vereinfachen:

// das funktioniert für bis zu 10 Elemente:
Map test1 = Map.of(
    "a", "b",
    "c", "d"
);

// das funktioniert für beliebig viele Elemente:
import static java.util.Map.entry;    
Map test2 = Map.ofEntries(
    entry("a", "b"),
    entry("c", "d")
);

In dem obigen Beispiel sind sowohl test als auch test2 gleich, nur mit unterschiedlichen Arten, die Map auszudrücken. Die Methode Map.of ist für bis zu zehn Elemente in der Map definiert, während die Methode Map.ofEntries keine solche Begrenzung hat.

Beachten Sie, dass in diesem Fall die resultierende Map eine unveränderliche Map sein wird. Wenn Sie möchten, dass die Map veränderbar ist, könnten Sie sie erneut kopieren, z.B. mit mutableMap = new HashMap<>(Map.of("a", "b"));. Beachten Sie auch, dass in diesem Fall Schlüssel und Werte nicht null sein dürfen.

(Siehe auch JEP 269 und die Javadoc)

Für bis zu Java Version 8:

Nein, Sie müssen alle Elemente manuell hinzufügen. Sie können einen Initialisierer in einer anonymen Unterklasse verwenden, um die Syntax etwas zu verkürzen:

Map myMap = new HashMap() {{
    put("a", "b");
    put("c", "d");
}};

Jedoch kann die anonyme Unterklasse in einigen Fällen unerwünschtes Verhalten hervorrufen. Dazu gehören zum Beispiel:

  • Es erzeugt eine zusätzliche Klasse, was den Speicherverbrauch, den Festplattenplatzverbrauch und die Startzeit erhöht
  • Im Falle einer nicht-statischen Methode: Es hält eine Referenz auf das Objekt, auf dem die erstellende Methode aufgerufen wurde. Das bedeutet, dass das Objekt der äußeren Klasse nicht freigegeben werden kann, solange das erstellte Map-Objekt noch referenziert wird und somit zusätzlichen Speicher blockiert

Die Verwendung einer Funktion zur Initialisierung ermöglicht es auch, eine Map in einem Initialisierer zu generieren, vermeidet jedoch unerwünschte Nebenwirkungen:

Map myMap = createMap();

private static Map createMap() {
    Map myMap = new HashMap();
    myMap.put("a", "b");
    myMap.put("c", "d");
    return myMap;
}

3 Stimmen

Dies funktioniert nicht, wenn Sie die Elemente in einer Funktion initialisieren möchten...

12 Stimmen

@Michael: Nun ja, wenn Sie eine Funktion verwenden möchten, können Sie keine Nicht-Funktion verwenden. Aber warum möchten Sie das?

11 Stimmen

Und für die Fälle, in denen Sie eine Karte mit einem einzigen Eintrag benötigen, gibt es Collections.singletonMap() :)

1165voto

gregory561 Punkte 14569

Dies ist eine Möglichkeit.

Map h = new HashMap() {{
    put("a","b");
}};

Dennoch sollten Sie vorsichtig sein und sicherstellen, dass Sie den obigen Code verstehen (er erstellt eine neue Klasse, die von HashMap erbt). Daher sollten Sie hier mehr lesen: http://www.c2.com/cgi/wiki?DoubleBraceInitialization , oder einfach Guava verwenden:

Map left = ImmutableMap.of("a", 1, "b", 2, "c", 3);

ImmutableMap.of funktioniert für bis zu 5 Einträge. Andernfalls verwenden Sie den Builder: source.

91 Stimmen

Es funktioniert, ist aber hässlich und hat unsichtbare Nebenwirkungen, die der Benutzer verstehen sollte, bevor er es tut - zum Beispiel das Erzeugen einer vollständig anonymen Klasse vor Ort.

110 Stimmen

Ja, deshalb schrieb ich darüber, vorsichtig zu sein und gab einen Link zur Beschreibung.

6 Stimmen

Toller Link. Der Verweis in diesem Link auf GreencoddsTenthRuleOfProgramming ist lesenswert.

371voto

Jens Hoffmann Punkte 6589

Wenn Sie 3rd-Party-Bibliotheken zulassen, können Sie mit Guava 's ImmutableMap eine literalähnliche Kürze erreichen:

Map test = ImmutableMap.of("k1", "v1", "k2", "v2");

Dies funktioniert bis zu 5 Schlüssel/Wert-Paare, andernfalls können Sie seinen Builder verwenden:

Map test = ImmutableMap.builder()
    .put("k1", "v1")
    .put("k2", "v2")
    ...
    .build();
  • beachten Sie, dass die Implementierung von Guavas ImmutableMap sich von der Implementierung von Javas HashMap unterscheidet (insbesondere ist sie unveränderlich und erlaubt keine null-Schlüssel/Werte)
  • für weitere Informationen finden Sie in Guavas Benutzerhandbuch Artikel über seine unveränderlichen Sammlungstypen

29 Stimmen

Auch Guave hat ImmutableMap.builder.put("k1","v1").put("k2","v2").build();

21 Stimmen

ImmutableMap ist nicht das gleiche wie eine HashMap, da es bei Nullwerten fehlschlägt, während die HashMap nicht.

4 Stimmen

Nur um anderen zu helfen, die auf dieses Problem stoßen könnten. Sie müssen den Builder eingeben, um daraus eine Map zu machen, wie zum Beispiel: Map test = ImmutableMap.builder().put("k1", "v1").put("k2", "v2").build();

122voto

Paŭlo Ebermann Punkte 70779

Es gibt keinen direkten Weg, dies zu tun - Stand 2021 hat Java keine Map-Literale (noch nicht - ich glaube, sie wurden für Java 8 vorgeschlagen, haben es aber nicht geschafft).

Einige Leute mögen das hier:

Map test = new HashMap(){{
       put("test","test"); put("test","test");}};

Dies erstellt eine anonyme Unterklasse von HashMap, deren Instanz-Initializer diese Werte setzt. (Übrigens, eine Map kann nicht zweimal den gleichen Wert enthalten, dein zweiter put überschreibt den ersten. Ich werde für die nächsten Beispiele unterschiedliche Werte verwenden.)

Der normale Weg wäre dieser (für eine lokale Variable):

Map test = new HashMap();
test.put("test","test");
test.put("test1","test2");

Wenn deine test Map eine Instanzvariable ist, platziere die Initialisierung in einem Konstruktor oder Instanzinitializer:

Map test = new HashMap();
{
    test.put("test","test");
    test.put("test1","test2");
}

Wenn deine test Map eine Klassenvariable ist, platziere die Initialisierung in einem statischen Initializer:

static Map test = new HashMap();
static {
    test.put("test","test");
    test.put("test1","test2");
}

Wenn du möchtest, dass deine Map sich nie ändert, solltest du nach der Initialisierung deine Map mit Collections.unmodifiableMap(...) umschließen. Du kannst dies auch in einem statischen Initializer tun:

static Map test;
{
    Map temp = new HashMap();
    temp.put("test","test");
    temp.put("test1","test2");
    test = Collections.unmodifiableMap(temp);
}

(Ich bin mir nicht sicher, ob du jetzt test final machen kannst ... probiere es aus und berichte hier.)

Seit Java 9 hast du auch die Map.of(...) und Map.ofEntries() Syntax, wie in der Antwort von yankee erklärt.

65voto

Shaggy Frog Punkte 27326
Map test = new HashMap()
{
    {
        put(key1, value1);
        put(key2, value2);
    }
};

0 Stimmen

Einfach und auf den Punkt gebracht. Ich denke, dass dies mit einer erweiterten Kommentarspalte die beste Antwort wäre.

0 Stimmen

Warum hat das nicht mehr Stimmen? Ist es nicht besser als die anderen Antworten? Ich finde es viel sauberer aus. Könnte mir das bitte jemand erklären? Denn ich könnte am Ende dieses hier verwenden. Vielen Dank.

17 Stimmen

Es gibt jedoch zu beachtende Speicherimplikationen. blog.jooq.org/2014/12/08/…

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X