2015-05-06 10 views
11

Stellen Sie sich das folgende Szenario vor. Sie haben eine Reihe von Werten, die bereits zugänglich und bekannt sind. Sie müssen sie aus Gründen in eine HashMap einfügen.Java HashMap - Ist es notwendig, .put() für jeden Satz zu verwenden?

Code-Beispiel:

String a = "a"; 
Strinb b = "b"; 
... 
HashMap map = new HashMap(5); 
map.put("a", a); 
map.put("b", b); 
... 

Ist es wirklich notwendig, es so zu tun? Ich kann nicht glauben, dass es keinen Konstruktor gibt, mit dem Sie Ihre Werte von Grund auf eingeben können.

Ich spreche über etwas wie folgt aus:

HashMap map = new HashMap(<"a", a>, <"b", b>, ...); 

Oder sogar etwas wie folgt aus:

HashMap map = new HashMap(5); 
HashMap.putBunchOfStuff("a", a, "b", b, ...); 

Edit: Meine Absicht war, zu fragen, ob es ein Verfahren ist, aber was noch wichtiger ist , Wenn die Antwort "Nein" ist, warum gibt es keinen solchen Konstruktor/Methode.

+0

Idk wenn Java8 einige neue Tricks hat oder nicht. Aber [diese] (http://stackoverflow.com/questions/507602/how-can-i-initial-ize-astatic-map) Frage wurde vor ein paar Jahren gestellt und der Konsens war nein. Siehe auch [dies] (http://stackoverflow.com/questions/6802483/how-to-directly-initialize-a-hashmap-in-a-literal-way) – chancea

+0

Sie können nicht so ... Aber Sie können fügen Sie eine weitere Karte hinzu, indem Sie putAll verwenden (Map (K, v)); –

+0

Ich frage mich, ob es von Anfang an zugänglich ist, warum verwenden Sie 'enums' nicht, oder wenn Sie keine Duplizierung für Schlüssel und Wert mögen, warum ist es dann nicht' Set', oder Sie können 'MyHashMap erstellen 'wo Sie definieren 'Put (Object o)' – CsBalazsHungary

Antwort

14

Leider Sammlung Literale waren proposal for Project Coin in Java 7 (und Java 8), aber machte es nie in das Endprodukt, auch bekannt als es kein Feature von Java ist.

Der Satz war

Here’s how it would look with map literals: 


    final Map<Integer, String> platonicSolids = { 
      4 : "tetrahedron", 
      6 : "cube", 
      8 : "octahedron", 
      12 : "dodecahedron", 
      20 : "icosahedron" 
    }; 


Here is the empty map literal, which has a slightly irregular syntax to make 
it differ from the empty set: 


    Map<String, Integer> noJokeHere = { : }; 

aber es ist nie passiert, so dass leider nicht funktioniert. Also, es sei denn, Sie schreiben Ihren eigenen Zauberer oder lambda wie on this site of Per-Åke Minborg, Sie sind auf sich allein gestellt. Folgendes von der Seite sollte allerdings funktionieren (in Java 8).

//copy paste from linked site 
Map<Integer, String> map = Stream.of(
      new SimpleEntry<>(0, "zero"), 
      new SimpleEntry<>(1, "one"), 
      //... 
      new SimpleEntry<>(11, "eleven"), 
      new SimpleEntry<>(12, "twelve")) 
      .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue())); 

Und das vereinfachte Version, die auch von der site:

//copy paste from linked site 
public static <K, V> Map.Entry<K, V> entry(K key, V value) { 
    return new AbstractMap.SimpleEntry<>(key, value); 
} 

public static <K, U> Collector<Map.Entry<K, U>, ?, Map<K, U>> entriesToMap() { 
    return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()); 
} 

Map<Integer, String> map = Stream.of(
      entry(0, "zero"), 
      //... 
      entry(12, "twelve")) 
      .collect(entriesToMap()); 

Sammlung Literale wurden nicht wegen these points eingeführt:

  • Der "einfache" Version dieses Features (Sätze, Listen, Karten nur) ist nicht sehr befriedigend oder populär; die "erweiterbare" Version dieses Features ist offen, unordentlich und praktisch garantiert, um seine Konstruktion zu übertreffen Budget;

  • Die Bibliothek-basierte Version gibt uns X% des Nutzens für 1% der Kosten, wobei X >> 1;

  • Werttypen kommen, und die in einer Welt mit Werttypen „was wie diese Funktion aussehen würde“ kann gut sein, ganz anders als in einer Welt ohne, was darauf hindeutet, es fraglich wäre, diese Arbeit zu versuchen und zu tun vor Werttypen;

  • Wir sind besser dran, unsere Sprache-Design Bandbreite auf Fokussierung mehr die grundlegenden Fragen Adressierung eine bibliotheksbasierten Version zugrunde liegen (zB: effizienter varargs, Array-Konstanten in dem konstanten Pool, unveränderliche Arrays und Unterstützung für Caching (und Rückgewinnung von unter Druck) zwischen unveränderlichen Ergebnissen).

By Brian Goetz from Oracle

+0

... du meinst die zweite, oder? Der erste war ein Vorschlag. Das ist niemals passiert. – EpicPandaForce

+2

Nein, ich habe über die Antwort im Allgemeinen gesprochen. Sehr schöne, klare Information und genau die INFO, nach der ich gesucht habe. Es war nicht meine Absicht, ein Code-Snippet zu greifen. – OddDev

+0

ah, in diesem Fall bin ich froh, dass Sie es hilfreich fanden, und Sie sind herzlich willkommen! :) – EpicPandaForce

1

Es gibt keine solche Konstruktor standardmäßig - Sie doppelt Klammer Idiom put alle Werte in der Karte auf der Instanzierung verwendet werden könnte, aber dies erfordert noch mehr Put-Anrufe:

Map<String,String> map = new HashMap<>() {{ 
    put("a", "val1"); 
    put("b", "val2"); 
    //etc. 
}}; 

In Wirklichkeit Sie haben in der Regel große Datenblöcke, die Sie in eine Karte einfügen möchten, auf die von einem Stream oder einer anderen Sammlung aus zugegriffen werden kann. In diesem Fall ist es also einfach, mehrere Aufrufe put zu durchlaufen.

Guava hat eine putAll() auf seiner, so dass Sie etwas Ähnliches vor der Instanziierung tun können. Andere externe Bibliotheken haben möglicherweise ein ähnliches Verhalten, aber Sie müssen auf externe Bibliotheken zurückgreifen.

+4

Hinweis: Bei der Doppelstrebeninitialisierung wird eine anonyme Unterklasse erstellt, die unter anderem einen starken Verweis auf die äußere Instanz behält (und somit am Leben erhält), wenn sie in einem nicht statischen Kontext verwendet wird. – Radiodef

+1

@Radiodef Das ist wahr - ich finde es nicht ein ideales Idiom (es ist eher ein Unfall der obskuren Syntax als etwas, das für diesen Zweck entwickelt wurde.) – berry120

0

Sie können so etwas verwenden:

HashMap<String, String> map = new HashMap<String, String>(5){{ 
    put("a", "a"); 
    put("b", "b"); 
}}; 

Aber ich weiß nicht, ob u mit lokalen Variablen a und b verwenden können.

+2

Hinweis: Dies erstellt eine anonyme Unterklasse, die unter anderem eine starke Referenz hält zu der äußeren Instanz (wodurch sie am Leben erhalten wird), wenn sie in einem nicht-statischen Kontext verwendet wird. – Radiodef

1

Es ist möglich, eine hübsche Hilfsmethode zu erstellen, um Karten mit varargs zu erstellen.

Beispiel:

@SuppressWarnings("unchecked") 
public static <K, V> HashMap<K, V> newMap(Object... elems) { 
    HashMap<K, V> m = new HashMap<K, V>(); 

    for (int i = 0; i < elems.length; i += 2) { 
     m.put((K) elems[i], (V) elems[i + 1]);  
    } 

    return m; 
} 

Map<String, Integer> m = newMap("k1", 1, "k2", 2);   

Vorsicht: Dies ist nicht sicher geben und in einer Karte mit Objekten der falschen Arten führen kann, wenn Sie einen Fehler machen, wenn es verwendet wird, ClassCastException an unerwarteten Orten zu werfen. Dies wird heap pollution genannt. Beispiel:

Map<String, Integer> m = newMap("k1", 1, "k2", "2"); 
int s = m.get("k2"); // ClassCastException! 
Verwandte Themen