Frage Wie kann ich eine statische Map initialisieren?


Wie würden Sie eine statische Map in Java initialisieren?

Methode eins: statischer Initialisierer
Methode 2: Instanzinitialisierer (anonyme Unterklasse) oder eine andere Methode?

Was sind die Vor- und Nachteile von jedem?

Hier ein Beispiel, das zwei Methoden veranschaulicht:

import java.util.HashMap;
import java.util.Map;

public class Test {
    private static final Map<Integer, String> myMap = new HashMap<Integer, String>();
    static {
        myMap.put(1, "one");
        myMap.put(2, "two");
    }

    private static final Map<Integer, String> myMap2 = new HashMap<Integer, String>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}

930
2018-02-03 15:41


Ursprung


Antworten:


Der Instanzinitialisierer ist in diesem Fall nur syntaktischer Zucker, richtig? Ich verstehe nicht, warum Sie eine extra anonyme Klasse brauchen, nur um sie zu initialisieren. Und es wird nicht funktionieren, wenn die Klasse, die erstellt wird, endgültig ist.

Sie können eine unveränderliche Map auch mit einem statischen Initialisierer erstellen:

public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

945
2017-08-31 13:58



Ich mag Guave Art der Initialisierung einer statischen, unveränderlichen Karte:

static final Map<Integer, String> MY_MAP = ImmutableMap.of(
    1, "one",
    2, "two"
);

Wie Sie sehen können, ist es sehr kurz (wegen der bequemen Fabrikmethoden in ImmutableMap).

Wenn Sie möchten, dass die Karte mehr als 5 Einträge enthält, können Sie sie nicht mehr verwenden ImmutableMap.of(). Versuchen Sie es stattdessen ImmutableMap.builder() Entlang dieser Linien:

static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
    .put(1, "one")
    .put(2, "two")
    // ... 
    .put(15, "fifteen")
    .build();

Weitere Informationen zu den Vorteilen der unveränderlichen Sammlungsprogramme von Guava finden Sie unter Unveränderbare Sammlungen erklärt in Guava Benutzerhandbuch.

(Eine Untergruppe von) Guava wurde früher genannt Google Sammlungen. Wenn Sie diese Bibliothek noch nicht in Ihrem Java-Projekt verwenden, habe ich stark empfehlen, es auszuprobieren! Guava hat sich schnell zu einer der beliebtesten und nützlichsten 3rd-Party-Bibliotheken für Java entwickelt andere SO-Nutzer stimmen zu. (Wenn Sie neu sind, gibt es einige ausgezeichnete Lernressourcen hinter diesem Link.)


Aktualisierung (2015): Wie für Java 8Nun, ich würde immer noch den Guava-Ansatz verwenden, weil es sauberer ist als alles andere. Wenn Sie keine Guava-Abhängigkeit wünschen, sollten Sie a einfache alte Init-Methode. Der Hack mit zweidimensionale Array- und Stream-API ist ziemlich hässlich, wenn Sie mich fragen, und wird hässlicher, wenn Sie eine Karte erstellen müssen, deren Schlüssel und Werte nicht vom selben Typ sind (wie Map<Integer, String> in der Frage).

Wie für die Zukunft der Guava im Allgemeinen, in Bezug auf Java 8, Louis Wasserman sagte das zurück im Jahr 2014 undaktualisieren] im Jahr 2016 wurde angekündigt, dass Guava 21 wird Java 8 benötigen und richtig unterstützen.


Aktualisierung (2016): Wie Tagir Valeev weist darauf hin, Java 9 wird es endlich sauber machen mit nichts als reinem JDK, indem man hinzufügt Convenience-Factory-Methoden für Sammlungen:

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);

370
2018-02-03 21:40



Ich würde ... benutzen:

public class Test {
    private static final Map<Integer, String> MY_MAP = createMap();

    private static Map<Integer, String> createMap() {
        Map<Integer, String> result = new HashMap<Integer, String>();
        result.put(1, "one");
        result.put(2, "two");
        return Collections.unmodifiableMap(result);
    }
}
  1. es vermeidet anonyme Klasse, die ich persönlich für einen schlechten Stil halte, und meide es
  2. es macht die Erstellung der Karte expliziter
  3. es macht Karte unmodifizierbar
  4. Da MY_MAP konstant ist, würde ich es als konstant bezeichnen

160
2017-07-15 21:29



Java 5 bietet diese kompaktere Syntax:

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};

157
2018-02-03 15:44



Ein Vorteil der zweiten Methode besteht darin, dass Sie sie umschließen können Collections.unmodifiableMap() um sicherzustellen, dass die Sammlung später nicht aktualisiert wird:

private static final Map<Integer, String> CONSTANT_MAP = 
    Collections.unmodifiableMap(new HashMap<Integer, String>() {{ 
        put(1, "one");
        put(2, "two");
    }});

 // later on...

 CONSTANT_MAP.put(3, "three"); // going to throw an exception!

80
2017-09-14 00:44



Hier ist ein Java 8 einzeiliger statischer Map Initializer:

private static final Map<String, String> EXTENSION_TO_MIMETYPE =
    Arrays.stream(new String[][] {
        { "txt", "text/plain" }, 
        { "html", "text/html" }, 
        { "js", "application/javascript" },
        { "css", "text/css" },
        { "xml", "application/xml" },
        { "png", "image/png" }, 
        { "gif", "image/gif" }, 
        { "jpg", "image/jpeg" },
        { "jpeg", "image/jpeg" }, 
        { "svg", "image/svg+xml" },
    }).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));

Bearbeiten: um a zu initialisieren Map<Integer, String> Wie in der Frage, Sie würden so etwas brauchen:

static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
        {1, "one"},
        {2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));

Edit (2): Es gibt eine bessere, mischtypfähige Version von i_am_zero, die einen Stream von new SimpleEntry<>(k, v) Anrufe. Überprüfen Sie diese Antwort: https://stackoverflow.com/a/37384773/3950982


52
2017-12-29 10:07



In Java 9:

private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");

Sehen JEP 269 für Details. JDK 9 erreicht Allgemeine Verfügbarkeit im September 2017.


39
2017-12-18 23:10



Mit Eclipse-Sammlungen (früher GS Sammlungen), wird alles Folgende funktionieren:

import java.util.Map;

import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;

public class StaticMapsTest
{
    private static final Map<Integer, String> MAP =
        Maps.mutable.with(1, "one", 2, "two");

    private static final MutableMap<Integer, String> MUTABLE_MAP =
       Maps.mutable.with(1, "one", 2, "two");


    private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();


    private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
        Maps.mutable.with(1, "one", 2, "two").asSynchronized();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").toImmutable();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
        Maps.immutable.with(1, "one", 2, "two");
}

Sie können auch primitive Maps mit Eclipse Collections statisch initialisieren.

import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;

public class StaticPrimitiveMapsTest
{
    private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two");

    private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asUnmodifiable();

    private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asSynchronized();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .toImmutable();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
            IntObjectMaps.immutable.<String>empty()
                    .newWithKeyValue(1, "one")
                    .newWithKeyValue(2, "two");
} 

Hinweis: Ich bin ein Committer für Eclipse Collections


27
2018-02-03 15:55