Jak mohu inicializovat statické mapy?

hlasů
913

Jak byste inicializovat statické mapy v Javě?

Způsob jedna: statický initialiser
Metoda dvě: instance initialiser (anonymní podtřídy), nebo nějakým jiným způsobem?

Jaké jsou výhody a nevýhody každého z nich?

Zde je příklad ilustrující dvě metody:

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);
        }
    };
}
Položena 03/02/2009 v 16:41
zdroj uživatelem
V jiných jazycích...                            


42 odpovědí

hlasů
79

Jednou z výhod druhé metody je, že ji můžete zabalit s Collections.unmodifiableMap () zajistit, aby se nic aktualizovat kolekce později:

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!
Odpovězeno 03/02/2009 v 16:44
zdroj uživatelem

hlasů
0

Druhá metoda by mohla vyvolat chráněné metody v případě potřeby. To může být užitečné pro inicializaci tříd, které jsou neměnné po dokončení stavby.

Odpovězeno 03/02/2009 v 16:45
zdroj uživatelem

hlasů
935

Instance initialiser je jen syntaktický cukr v tomto případě, je to tak? Nevidím důvod, proč budete potřebovat další anonymní třídu jen pro inicializaci. A to nebude fungovat, pokud je třída vznikají je konečné.

Můžete vytvořit neměnný mapy pomocí statické initialiser příliš:

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);
    }
}
Odpovězeno 03/02/2009 v 16:51
zdroj uživatelem

hlasů
24

Nikdy bych vytvořit anonymní podtřídu v této situaci. Statické inicializátory fungovat stejně dobře, pokud byste chtěli, aby se mapa unmodifiable například:

private static final Map<Integer, String> MY_MAP;
static
{
    Map<Integer, String>tempMap = new HashMap<Integer, String>();
    tempMap.put(1, "one");
    tempMap.put(2, "two");
    MY_MAP = Collections.unmodifiableMap(tempMap);
}
Odpovězeno 03/02/2009 v 16:55
zdroj uživatelem

hlasů
0

Líbí se mi syntaxi anonymní třídy; je to jen méně kódu. Nicméně, jeden major con Zjistil jsem, že nebudete moci serializaci daný objekt prostřednictvím vzdálené komunikace. Dostanete výjimku o není schopen najít anonymní třídu na vzdálené straně.

Odpovězeno 03/02/2009 v 17:18
zdroj uživatelem

hlasů
4

Anonymní třída budete vytvářet funguje dobře. Nicméně byste měli být vědomi toho, že se jedná o vnitřní třídy a jako takový bude obsahovat odkaz na okolní instanci třídy. Tak zjistíte, nemůžete dělat určité věci s ním (s použitím Xstream jednoho). Dostanete některé velmi podivné chyby.

Který uvedl, že pokud jste si vědom pak tento přístup je v pořádku. Používám ho většinu času pro inicializaci všech druhů kolekcí ve stručné způsobem.

EDIT: poukázal správně v komentářích, že se jedná o statickou třídu. Je zřejmé, Nečetl jsem to dost blízko. Nicméně mé komentáře se nadále používat pro anonymní vnitřní třídy.

Odpovězeno 03/02/2009 v 17:31
zdroj uživatelem

hlasů
0

Udělal jsem něco trochu jiného. Není to nejlepší, ale funguje to pro mě. Možná, že by to mohlo být „genericized“.

private static final Object[][] ENTRIES =
{
  {new Integer(1), "one"},
  {new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);

private static Map newMap(Object[][] entries)
{
  Map map = new HashMap();

  for (int x = 0; x < entries.length; x++)
  {
    Object[] entry = entries[x];

    map.put(entry[0], entry[1]);
  }

  return map;
}
Odpovězeno 03/02/2009 v 19:40
zdroj uživatelem

hlasů
14

Možná je to zajímavé vyzkoušet Google sbírek , například videa, které mají na své straně. Poskytují různé způsoby, jak inicializaci mapy a soubory a poskytují neměnné kolekce stejně.

Aktualizace: Tato knihovna je nyní pojmenovaná Guava .

Odpovězeno 03/02/2009 v 22:33
zdroj uživatelem

hlasů
159

Chtěl bych použít:

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. vyhýbá anonymní třídu, což já osobně považuji za špatný styl, a vyhnout
  2. to dělá vytvoření mapy jasněji
  3. to dělá mapa unmodifiable
  4. as MY_MAP je konstantní, tak bych to pojmenovat jako konstantní
Odpovězeno 03/02/2009 v 22:40
zdroj uživatelem

hlasů
156

Java 5 poskytuje tuto kompaktnější syntaxi:

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};
Odpovězeno 15/07/2009 v 22:29
zdroj uživatelem

hlasů
9
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);
    }
}

Pokud budeme deklarovat více než jednu konstantu pak tento kód bude zapsán ve statickém bloku, a to je těžké udržet v budoucnu. Takže je lepší použít anonymní třídu.

public class Test {

    public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
        {
            put(1, "one");
            put(2, "two");
        }
    });
}

A je navrženo použitého unmodifiableMap jiných konstanty moudrý, že nemůže být zacházeno jako konstantní.

Odpovězeno 03/06/2010 v 09:18
zdroj uživatelem

hlasů
7

Mohl bych silně naznačují, že „double inicializační rovnátka“ styl přes statické jednotného stylu.

Někdo se může vyjádřit, že nemají rádi anonymní třídu, nad hlavou, výkon, atd

Ale to jsem ještě zvážit, je kód čitelnost a udržovatelnost. V tomto pohledu, stojím dvojitá výztuha je lepší styl kódu spíše než statické metody.

  1. Tyto prvky jsou vnořené a inline.
  2. To je více OO, ne procesní.
  3. dopad výkon je opravdu malý a může být ignorováno.
  4. Lepší IDE obrys podpora (spíše než mnoho anonymní statické {} bloku)
  5. Zachránil jste několik řádků komentáře, aby jim vztah.
  6. Se zabránilo možnému úniku prvek / instance vedení neinicializované objektu z výjimek a bytecode optimalizátoru.
  7. Žádné starosti o pořadí provádění statického bloku.

Kromě toho, že si vědomi GC anonymního třídě, vždy můžete převést na normální HashMap pomocí new HashMap(Map map).

Můžete to udělat, dokud čelí další problém. Pokud ano, měli byste použít dokončit jiný styl kódování (např žádné statické, tovární třída) za to.

Odpovězeno 12/12/2010 v 05:29
zdroj uživatelem

hlasů
359

Líbí se mi Guava způsob inicializace statické, neměnné mapu:

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

Jak vidíte, je to velmi stručné (z důvodu výhodných výrobních metod v ImmutableMap).

Pokud se chcete mapy že mají více než 5 záznamů, můžete nadále používat ImmutableMap.of(). Místo toho se snaží ImmutableMap.builder()v tomto duchu:

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

Chcete-li se dozvědět více o výhodách neměnných sběrných utilit guava, viz neměnná kolekce vysvětlil v uživatelské příručce Guava .

(A podmnožina) Guava říkalo Google sbírky . Pokud jste se dosud s použitím této knihovny v projektu Java, jsem důrazně doporučujeme snažil to! Guava se rychle stal jedním z nejpopulárnějších a užitečné volně knihovnami 3. stran pro Javu, jako kolega SO uživatelé souhlasí . (Pokud jste k tomu, tam jsou některé vynikající výukové zdroje za tímto odkazem.)


Update (2015) : Stejně jako u Javy 8 , no, já bych ještě používat přístup Guava, protože to je způsob, čistší, než cokoliv jiného. Pokud si nepřejete závislost Guava uvažujme obyčejný starý init metoda . Hack s dvojrozměrné pole a Stream API je docela ošklivý, pokud se mě ptáte, a dostane ošklivější, pokud potřebujete vytvořit mapu, jejíž klíče a hodnoty nejsou stejného typu (podobně jako Map<Integer, String>v otázce).

Pokud jde o budoucnost Guava obecně, s ohledem na Javě 8 Louis Wasserman řekl již v roce 2014, a [ aktualizace ] V roce 2016 bylo oznámeno, že Guava 21 bude vyžadovat i náležitě podporovat Java 8 .


Update (2016) : Jak Tagir Valeev poukazuje na to , Java 9 bude konečně dělat to clean dělat nic jiného, než s použitím čistého JDK, přidáním pohodlí tovární metody pro sbírek:

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);
Odpovězeno 31/08/2011 v 14:58
zdroj uživatelem

hlasů
2

Nemám rád statické syntaxi Inicializátor a nejsem přesvědčen o tom anonymním podtřídy. Obecně platí, že souhlasím se všemi zápory pomocí statických inicializátory a všechny nevýhody používání anonymních podtřídy, které byly uvedeny v minulém odpovědi. Na druhou stranu - klady uvedené v těchto pracovních míst nejsou dost pro mě. Raději používat statické metody inicializace:

public class MyClass {
    private static final Map<Integer, String> myMap = prepareMap();

    private static Map<Integer, String> prepareMap() {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "one");
        hashMap.put(2, "two");

        return hashMap;
    }
}
Odpovězeno 27/08/2012 v 07:09
zdroj uživatelem

hlasů
27

S Eclipse sbírek (dříve GS sbírky ), ve všech těchto oblastech bude fungovat:

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

Můžete také staticky inicializaci primitivní map s Eclipse sbírek.

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

Poznámka: Jsem vývojář pro Eclipse sbírek

Odpovězeno 19/12/2012 v 00:10
zdroj uživatelem

hlasů
3

Pokud chcete něco lakonické a relativně bezpečné, stačí posunout typ kompilace-time kontrola na run-time:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(
    String.class, Integer.class,
    "cat",  4,
    "dog",  2,
    "frog", 17
);

Tato implementace by měla zachytit případné chyby:

import java.util.HashMap;

public abstract class MapUtils
{
    private MapUtils() { }

    public static <K, V> HashMap<K, V> unmodifiableMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        return Collections.<K, V>unmodifiableMap(makeMap(
            keyClazz,
            valClazz,
            keyValues));
    }

    public static <K, V> HashMap<K, V> makeMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        if (keyValues.length % 2 != 0)
        {
            throw new IllegalArgumentException(
                    "'keyValues' was formatted incorrectly!  "
                  + "(Expected an even length, but found '" + keyValues.length + "')");
        }

        HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);

        for (int i = 0; i < keyValues.length;)
        {
            K key = cast(keyClazz, keyValues[i], i);
            ++i;
            V val = cast(valClazz, keyValues[i], i);
            ++i;
            result.put(key, val);
        }

        return result;
    }

    private static <T> T cast(Class<? extends T> clazz, Object object, int i)
    {
        try
        {
            return clazz.cast(object);
        }
        catch (ClassCastException e)
        {
            String objectName = (i % 2 == 0) ? "Key" : "Value";
            String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
            throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
        }
    }
}
Odpovězeno 02/08/2013 v 02:30
zdroj uživatelem

hlasů
13

Mám rád anonymní třídu, protože je snadné se s tím vyrovnat:

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
    {
        put(1, "some value");
                    //rest of code here
    }
});
Odpovězeno 19/09/2013 v 09:48
zdroj uživatelem

hlasů
0

Pokud můžete použít řetězcové vyjádření vašich dat se jedná o možnost příliš v Javě 8:

static Map<Integer, String> MAP = Stream.of(
        "1=one",
        "2=two"
).collect(Collectors.toMap(k -> Integer.parseInt(k.split("=")[0]), v -> v.split("=")[1]));
Odpovězeno 13/01/2014 v 05:39
zdroj uživatelem

hlasů
0

Nyní, když Java 8, tato otázka zaručuje přehodnocení. Vzal jsem si píchnout do ní - vypadá možná můžete využít syntaxe výraz lambda dostat docela pěkné a přehledné (ale typ-safe) mapa syntaxe literálu, který vypadá takto:

        Map<String,Object> myMap = hashMap(
                bob -> 5,
                TheGimp -> 8,
                incredibleKoolAid -> "James Taylor",
                heyArnold -> new Date()
        );

        Map<String,Integer> typesafeMap = treeMap(
                a -> 5,
                bee -> 8,
                sea -> 13
                deep -> 21
        );

Nevyzkoušený ukázkový kód na https://gist.github.com/galdosd/10823529 Bude zvědavý na názory ostatních na to (to je mírně zlo ...)

Odpovězeno 16/04/2014 v 08:32
zdroj uživatelem

hlasů
3

Dávám přednost použití statického inicializátor, aby se zabránilo vytváření anonymní třídy (což by žádný další účel), takže budu seznam tipů inicializace se statickou inicializátor. Všechny uvedené řešení / tipy jsou typově bezpečné.

Poznámka: Otázka neříká nic o tom, dělat mapa unmodifiable, takže nechám to ven, ale vím, že to může snadno být provedeno Collections.unmodifiableMap(map).

první tip

1. tip je, že můžete udělat místní odkaz na mapu a můžete ji dát Krátký název:

private static final Map<Integer, String> myMap = new HashMap<>();
static {
    final Map<Integer, String> m = myMap; // Use short name!
    m.put(1, "one"); // Here referencing the local variable which is also faster!
    m.put(2, "two");
    m.put(3, "three");
}

druhý tip

2. tip je, že můžete vytvořit pomocnou metodu přidat položky; můžete také tento pomocník metodu veřejnosti, chcete-li:

private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
    p(1, "one"); // Calling the helper method.
    p(2, "two");
    p(3, "three");
}

private static void p(Integer k, String v) {
    myMap2.put(k, v);
}

Pomocník metoda zde není znovu použitelná, protože i když to může jen přidat prvky myMap2. Aby to bylo opakovaně použitelné, mohli bychom udělat mapy sám parametr metody pomocník, ale pak inicializace kód by neměl být žádný kratší.

třetí tip

3. tip je, že můžete vytvořit opakovaně použitelné stavitel-like pomocnou třídu s funkčností naplnění. To je opravdu jednoduchý, 10 řádek pomocník třídy, který je typově bezpečné:

public class Test {
    private static final Map<Integer, String> myMap3 = new HashMap<>();
    static {
        new B<>(myMap3)   // Instantiating the helper class with our map
            .p(1, "one")
            .p(2, "two")
            .p(3, "three");
    }
}

class B<K, V> {
    private final Map<K, V> m;

    public B(Map<K, V> m) {
        this.m = m;
    }

    public B<K, V> p(K k, V v) {
        m.put(k, v);
        return this; // Return this for chaining
    }
}
Odpovězeno 22/04/2014 v 09:46
zdroj uživatelem

hlasů
49

Zde je Java 8 jednořádkový statická mapa Inicializátor:

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

Edit: inicializovat Map<Integer, String>jako v otázce, kterou je třeba něco takového:

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]));
Odpovězeno 14/09/2014 v 01:44
zdroj uživatelem

hlasů
0

Líbí se mi pomocí statické inicializátor „technika“, když mám realizaci konkrétního z abstraktní třídy, která je definována inicializace konstruktor ale žádný výchozí konstruktor, ale já chci, aby moje podtřídy mít výchozí konstruktor.

Například:

public abstract class Shape {

    public static final String COLOR_KEY = "color_key";
    public static final String OPAQUE_KEY = "opaque_key";

    private final String color;
    private final Boolean opaque;

    /**
     * Initializing constructor - note no default constructor.
     *
     * @param properties a collection of Shape properties
     */
    public Shape(Map<String, Object> properties) {
        color = ((String) properties.getOrDefault(COLOR_KEY, "black"));
        opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);
    }

    /**
     * Color property accessor method.
     *
     * @return the color of this Shape
     */
    public String getColor() {
        return color;
    }

    /**
     * Opaque property accessor method.
     *
     * @return true if this Shape is opaque, false otherwise
     */
    public Boolean isOpaque() {
        return opaque;
    }
}

a můj konkrétní realizace této třídě - ale chce / potřebuje výchozí konstruktor:

public class SquareShapeImpl extends Shape {

    private static final Map<String, Object> DEFAULT_PROPS = new HashMap<>();

    static {
        DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");
        DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);
    }

    /**
     * Default constructor -- intializes this square to be a translucent yellow
     */
    public SquareShapeImpl() {
        // the static initializer was useful here because the call to 
        // this(...) must be the first statement in this constructor
        // i.e., we can't be mucking around and creating a map here
        this(DEFAULT_PROPS);
    }

    /**
     * Initializing constructor -- create a Square with the given
     * collection of properties.
     *
     * @param props a collection of properties for this SquareShapeImpl
     */
    public SquareShapeImpl(Map<String, Object> props) {
        super(props);
    }
}

Potom použít tuto výchozí konstruktor, prostě udělat:

public class StaticInitDemo {

    public static void main(String[] args) {

        // create a translucent, yellow square...
        Shape defaultSquare = new SquareShapeImpl();

        // etc...
    }
}
Odpovězeno 28/01/2015 v 21:35
zdroj uživatelem

hlasů
0

Četl jsem odpovědi a já jsem se rozhodl napsat vlastní mapu stavitel. Neváhejte a copy-paste a užívat si.

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

/**
 * A tool for easy creation of a map. Code example:<br/>
 * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
 * @param <K> key type (inferred by constructor)
 * @param <V> value type (inferred by constructor)
 * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
 */
public class MapBuilder <K, V> {
    private Map<K, V> map = new HashMap<>();

    /** Constructor that also enters the first entry. */
    private MapBuilder(K key, V value) {
        and(key, value);
    }

    /** Factory method that creates the builder and enters the first entry. */
    public static <A, B> MapBuilder<A, B> of(A key, B value) {
        return new MapBuilder<>(key, value);
    }

    /** Puts the key-value pair to the map and returns itself for method chaining */
    public MapBuilder<K, V> and(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * If no reference to builder is kept and both the key and value types are immutable,
     * the resulting map is immutable.
     * @return contents of MapBuilder as an unmodifiable map.
     */
    public Map<K, V> build() {
        return Collections.unmodifiableMap(map);
    }
}

EDIT: V poslední době jsem se držet hledání public static metodu ofpoměrně často a já se docela líbí. To jsem přidal do kódu a dělal konstruktoru jako soukromý, tedy přechod na statickou tovární metodu vzor.

Odpovězeno 20/05/2015 v 09:13
zdroj uživatelem

hlasů
1

Neviděl jsem přístup používám (a staly líbí) přispíval v jakékoliv odpovědi, takže tady je:

Nemám rád pomocí statických inicializátory protože jsou neohrabaný, a nemám rád anonymní třídy, protože to vytváří novou třídu pro každou instanci.

Místo toho raději inicializace, který vypadá takto:

map(
    entry("keyA", "val1"),
    entry("keyB", "val2"),
    entry("keyC", "val3")
);

Bohužel, tyto metody nejsou součástí standardní knihovny Java, takže budete muset vytvořit (nebo použití) užitný knihovny, která definuje následující metody:

 public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
 public static <K,V> Map.Entry<K,V> entry(K key, V val)

(Můžete použít ‚import statické‘, aby se zabránilo nutnosti prefix názvu této metody)

Zjistil jsem, že je užitečné, aby podobné statické metody pro jiné sbírky (seznam, nastavení, sortedSet, sortedMap, atd.)

Jeho ne tak hezky jako inicializace JSON objektu, ale je to krok v tomto směru, pokud jde o čitelnost.

Odpovězeno 03/06/2015 v 20:46
zdroj uživatelem

hlasů
0

V Javě 8, procesní přístup může také být zabaleny v Supplier:

Map<String,String> m = ((Supplier<Map<String,String>>)(() -> {
    Map<String,String> result = new HashMap<>();
    result.put("foo","hoo");
    ...
    return result;
)).get();

Je to jediný způsob, jak hypotetická, ale může přijít vhod, pokud opravdu potřebujete jednu vložku.

Odpovězeno 06/08/2015 v 16:10
zdroj uživatelem

hlasů
7

Jako obvykle Apache Commons vhodné metody MapUtils.putAll (MAP, Object []) :

Například k vytvoření barevné mapy:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
     {"RED", "#FF0000"},
     {"GREEN", "#00FF00"},
     {"BLUE", "#0000FF"}
 });
Odpovězeno 08/09/2015 v 09:32
zdroj uživatelem

hlasů
2

S Javou 8 Přišel jsem se použít následující vzorec:

private static final Map<String, Integer> MAP = Stream.of(
    new AbstractMap.SimpleImmutableEntry<>("key1", 1),
    new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Není to nejvíce strohý a trochu kolotoč, ale

  • nevyžaduje nic mimo java.util
  • je to typesafe a snadno pojme různé typy pro klíče a hodnoty.
Odpovězeno 20/11/2015 v 00:26
zdroj uživatelem

hlasů
35

V Javě 9:

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

Viz JEP 269 podrobnosti. JDK 9 dosáhla všeobecnou dostupnost v září 2017.

Odpovězeno 29/12/2015 v 10:07
zdroj uživatelem

hlasů
0

Tam jsou některé dobré odpovědi tady, ale chci nabídnout ještě jednou.

Vytvořte si vlastní statické metody pro vytvoření a inicializovat Map. Mám svou vlastní CollectionUtilstřídu v balení, které mohu použít ve více projektech s různými nástroji, které jsem pravidelně, které lze snadno použít pro mě psát a odstraňuje potřebu závislost na nějaké větší knihovny.

Tady je moje newMapmetoda:

public class CollectionUtils {
    public static Map newMap(Object... keyValuePairs) {
        Map map = new HashMap();
        if ( keyValuePairs.length % 2 == 1 ) throw new IllegalArgumentException("Must have even number of arguments");
        for ( int i=0; i<keyValuePairs.length; i+=2 ) {
            map.put(keyValuePairs[i], keyValuePairs[i + 1]);
        }
        return map;
    }
}

Používání:

import static CollectionUtils.newMap;
// ...
Map aMap = newMap("key1", 1.23, "key2", 2.34);
Map bMap = newMap(objKey1, objVal1, objKey2, objVal2, objKey3, objVal3);
// etc...

To neznamená, že využívání generik, ale můžete obsadit mapy, jak si přejete (stačí být jisti, že ji správně obsadit!)

Map<String,Double> aMap = (Map<String,Double>)newMap("key1", 1.23, "key2", 2.34);
Odpovězeno 28/01/2016 v 16:20
zdroj uživatelem

hlasů
2

Vzhledem k tomu, Java nepodporuje mapové literals instance mapa musí být vždy výslovně instance a naplněna.

Naštěstí je možné přiblížit chování mapových literálů v jazyce Java s využitím továrních metod .

Například:

public class LiteralMapFactory {

    // Creates a map from a list of entries
    @SafeVarargs
    public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
        LinkedHashMap<K, V> map = new LinkedHashMap<>();
        for (Map.Entry<K, V> entry : entries) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }
    // Creates a map entry
    public static <K, V> Map.Entry<K, V> entry(K key, V value) {
        return new AbstractMap.SimpleEntry<>(key, value);
    }

    public static void main(String[] args) {
        System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));
    }
}

Výstup:

{A = 1, b = 2, c = 3}

Je to mnohem pohodlnější než vytváření a naplnění mapou prvek najednou.

Odpovězeno 26/02/2016 v 21:53
zdroj uživatelem

hlasů
1

JEP 269 poskytuje určité pohodlí tovární metody API sbírek. Tato továrna metody nejsou v aktuální verzi Java, což je 8, ale jsou plánovány pro Java 9. vydání.

Pro Mapexistují dva tovární metody: ofa ofEntries. Používáte of, můžete předat střídající páry klíč / hodnota. Například za účelem vytvoření Mapjako {age: 27, major: cs}:

Map<String, Object> info = Map.of("age", 27, "major", "cs");

V současné době existuje deset přetížené verze pro of, takže si můžete vytvořit mapu obsahující deset párů klíč / hodnota. Pokud se vám nelíbí toto omezení nebo střídavý klíč / hodnoty, můžete použít ofEntries:

Map<String, Object> info = Map.ofEntries(
                Map.entry("age", 27),
                Map.entry("major", "cs")
);

Obě ofa ofEntriesvrátí neměnný Map, takže není možné měnit jejich prvků po dokončení stavby. Si můžete vyzkoušet tyto funkce pomocí JDK 9 včasný přístup .

Odpovězeno 10/04/2016 v 15:08
zdroj uživatelem

hlasů
12

Tam je odpověď navržený Lukášem, který inicializuje mapy pomocí Java 8, ale IMHO to vypadá ošklivě a těžko čitelné. Můžeme vytvořit proud záznamů mapy. Už máme dvě implementace Entryv java.util.AbstractMapnichž jsou SimpleEntry a SimpleImmutableEntry . Pro tento příklad můžeme využít bývalé as:

import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
            new SimpleEntry<>(1, "one"),
            new SimpleEntry<>(2, "two"),
            new SimpleEntry<>(3, "three"),
            new SimpleEntry<>(4, "four"),
            new SimpleEntry<>(5, "five"),
            new SimpleEntry<>(6, "six"),
            new SimpleEntry<>(7, "seven"),
            new SimpleEntry<>(8, "eight"),
            new SimpleEntry<>(9, "nine"),
            new SimpleEntry<>(10, "ten"))
            .collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));

For Java 9 můžeme také využít Map.ofjak navrhl Tagir v jeho odpovědi zde .

Odpovězeno 23/05/2016 v 07:17
zdroj uživatelem

hlasů
4

Tady je moje oblíbená, když nechci, aby (nebo nemohou) používat Guava je ImmutableMap.of(), nebo pokud potřebuji proměnlivý Map:

public static <A> Map<String, A> asMap(Object... keysAndValues) {
    return new LinkedHashMap<String, A>() {{
        for (int i = 0; i < keysAndValues.length - 1; i++) {
            put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
        }
    }};
}

Je velmi kompaktní a ignoruje zbloudilé hodnot (tj konečné klíč bez hodnoty).

Používání:

Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
Odpovězeno 15/09/2016 v 12:09
zdroj uživatelem

hlasů
0

Zde je kód by AbacusUtil

Map<Integer, String> map = N.asMap(1, "one", 2, "two");
// Or for Immutable map 
ImmutableMap<Integer, String> = ImmutableMap.of(1, "one", 2, "two");

Prohlášení: Jsem vývojář AbacusUtil.

Odpovězeno 28/11/2016 v 23:17
zdroj uživatelem

hlasů
0

I s guava je pěkné třídy ImmutableMap, někdy bych chtěl vybudovat proměnlivé mapy plynule. Nalezení sám chce, aby se zabránilo statické bloky & anonymní podtyp věc, když Java 8 přišla jsem napsal malou knihovnu na pomoc nazývá Fluent .

// simple usage, assuming someMap is a Map<String, String> already declared
Map<String, String> example = new Fluent.HashMap<String, String>()
    .append("key1", "val1")
    .append("key2", "val2")
    .appendAll(someMap);

S 8 rozhraní Java neplnící jsem mohl realizovat metody Fluent.Map pro všechny standardní implementace Java Map (tj HashMap, ConcurrentSkipListMap, ... atd) bez zdlouhavého opakování.

Unmodifiable mapy jsou příliš jednoduché.

Map<String, Integer> immutable = new Fluent.LinkedHashMap<String, Integer>()
    .append("one", 1)
    .append("two", 2)
    .append("three", 3)
    .unmodifiable();

Viz https://github.com/alexheretic/fluent pro zdroj, dokumentaci a příklady.

Odpovězeno 30/11/2016 v 01:16
zdroj uživatelem

hlasů
0

Pokud potřebujete jen přidat jednu hodnotu na mapu můžete použít Collections.singletonMap :

Map<K, V> map = Collections.singletonMap(key, value)
Odpovězeno 30/04/2017 v 21:28
zdroj uživatelem

hlasů
1

Váš druhý přístup (Double Brace inicializace) je myšlenka být proti vzor , takže bych jít pro první přiblížení.

Další snadný způsob, jak inicializovat statické mapy je pomocí této utility funkce:

public static <K, V> Map<K, V> mapOf(Object... keyValues) {
    Map<K, V> map = new HashMap<>(keyValues.length / 2);

    for (int index = 0; index < keyValues.length / 2; index++) {
        map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);
    }

    return map;
}

Map<Integer, String> map1 = mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");

Poznámka: v Java 9můžete použít Map.of

Odpovězeno 23/05/2017 v 09:29
zdroj uživatelem

hlasů
3

Můžete použít StickyMapi MapEntryod Cactoos :

private static final Map<String, String> MAP = new StickyMap<>(
  new MapEntry<>("name", "Jeffrey"),
  new MapEntry<>("age", "35")
);
Odpovězeno 20/06/2017 v 17:28
zdroj uživatelem

hlasů
1

No ... mám rád výčty)

enum MyEnum {
    ONE   (1, "one"),
    TWO   (2, "two"),
    THREE (3, "three");

    int value;
    String name;

    MyEnum(int value, String name) {
        this.value = value;
        this.name = name;
    }

    static final Map<Integer, String> MAP = Stream.of( values() )
            .collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}
Odpovězeno 25/10/2017 v 16:28
zdroj uživatelem

hlasů
5

Pokud chcete, nemůžete měnit mapy, konečně java 9 přidal chladný tovární metodu ofpro Maprozhraní. Podobná metoda se přidá k nastavení, seznam stejně.

Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");

Odpovězeno 26/11/2017 v 03:38
zdroj uživatelem

hlasů
0

Poznámka: Tato odpověď vlastně patří k otázce , jak se přímo inicializovat HashMap (v doslovném smyslu)? ale protože to je označen jako [duplikát] tohohle ...


Před Javě 9 s jejím Map.of () (který je také omezena na 10 mapování), můžete rozšířit Mapimplementaci vlastního výběru, například:

public class InitHashMap<K, V> extends HashMap<K, V>

znovu zavést HashMap‚s konstruktérů:

public InitHashMap() {
    super();
}

public InitHashMap( int initialCapacity, float loadFactor ) {
    super( initialCapacity, loadFactor );
}

public InitHashMap( int initialCapacity ) {
    super( initialCapacity );
}

public InitHashMap( Map<? extends K, ? extends V> m ) {
    super( m );
}

a přidat další konstruktor, který je inspirovaný Aerthel své odpovědi , ale je obecný pomocí Object...a <K, V>typů:

public InitHashMap( final Object... keyValuePairs ) {

    if ( keyValuePairs.length % 2 != 0 )
        throw new IllegalArgumentException( "Uneven number of arguments." );

    K key = null;
    int i = -1;

    for ( final Object keyOrValue : keyValuePairs )
        switch ( ++i % 2 ) {
            case 0:  // key
                if ( keyOrValue == null )
                    throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is <null>." );
                key = (K) keyOrValue;
                continue;
            case 1:  // value
                put( key, (V) keyOrValue );
        }
}

Běh

public static void main( final String[] args ) {

    final Map<Integer, String> map = new InitHashMap<>( 1, "First", 2, "Second", 3, "Third" );
    System.out.println( map );
}

Výstup

{1=First, 2=Second, 3=Third}

Můžete také rozšířit Maprozhraní podobně:

public interface InitMap<K, V> extends Map<K, V> {

    static <K, V> Map<K, V> of( final Object... keyValuePairs ) {

        if ( keyValuePairs.length % 2 != 0 )
            throw new IllegalArgumentException( "Uneven number of arguments." );

        final Map<K, V> map = new HashMap<>( keyValuePairs.length >> 1, .75f );
        K key = null;
        int i = -1;

        for ( final Object keyOrValue : keyValuePairs )
            switch ( ++i % 2 ) {
                case 0: // key
                    if ( keyOrValue == null )
                        throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is <null>." );
                    key = (K) keyOrValue;
                    continue;
                case 1: // value
                    map.put( key, (V) keyOrValue );
            }
        return map;
    }
}

Běh

public static void main( final String[] args ) {

    System.out.println( InitMap.of( 1, "First", 2, "Second", 3, "Third" ) );
}

Výstup

{1=First, 2=Second, 3=Third}
Odpovězeno 10/09/2018 v 23:59
zdroj uživatelem

hlasů
0

Ten využívá Apache Commons-lang, který bude s největší pravděpodobností na cestě třídy již:

Map<String, String> collect = Stream.of(
        Pair.of("hello", "world"),
        Pair.of("abc", "123"),
        Pair.of("java", "eight")
).collect(Collectors.toMap(Pair::getKey, Pair::getValue));
Odpovězeno 25/06/2019 v 11:39
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more