Drucken Sie eine Karte in Java aus

136

Ich suche nach einer schönen Möglichkeit, a hübsch zu drucken Map.

map.toString() gibt mir: {key1=value1, key2=value2, key3=value3}

Ich möchte mehr Freiheit bei meinen Karteneintragswerten und suche etwas Ähnliches: key1="value1", key2="value2", key3="value3"

Ich habe diesen kleinen Code geschrieben:

StringBuilder sb = new StringBuilder();
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Entry<String, String> entry = iter.next();
    sb.append(entry.getKey());
    sb.append('=').append('"');
    sb.append(entry.getValue());
    sb.append('"');
    if (iter.hasNext()) {
        sb.append(',').append(' ');
    }
}
return sb.toString();

Ich bin mir jedoch sicher, dass es dafür einen eleganteren und prägnanteren Weg gibt.

space_monkey
quelle
1
Mögliches Duplikat von Map to String in Java, da das hier angeforderte Format und das von System.out.printlnzu nahe beieinander liegen. Und wenn Sie etwas Benutzerdefiniertes wollen, läuft dies darauf hinaus, "wie man eine Karte in Java durchläuft", was sicherlich viele andere Antworten hat.
Ciro Santilli 法轮功 冠状 病 六四 事件 2

Antworten:

63

Oder bringen Sie Ihre Logik in eine ordentliche kleine Klasse.

public class PrettyPrintingMap<K, V> {
    private Map<K, V> map;

    public PrettyPrintingMap(Map<K, V> map) {
        this.map = map;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        Iterator<Entry<K, V>> iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<K, V> entry = iter.next();
            sb.append(entry.getKey());
            sb.append('=').append('"');
            sb.append(entry.getValue());
            sb.append('"');
            if (iter.hasNext()) {
                sb.append(',').append(' ');
            }
        }
        return sb.toString();

    }
}

Verwendung:

Map<String, String> myMap = new HashMap<String, String>();

System.out.println(new PrettyPrintingMap<String, String>(myMap));

Hinweis: Sie können diese Logik auch in eine Dienstprogrammmethode einfügen.

adarshr
quelle
3
Dies ist ein Antimuster imho. Sie fügen Ihrem Typ eine starke Einschränkung (Vererbung) hinzu, nur um geringfügige Vorteile zu erzielen (hübsches Drucken). Sie sollten eine normale Karte verwenden, aber eine statische Methode verwenden, die sie als Argument verwendet.
OoDeLally
304
Arrays.toString(map.entrySet().toArray())
Arkadiusz Cieśliński
quelle
11
Nicht so gut, wenn Sie haben Map<String, Map<String,double[]>>, dann bekommen Sie diese Art von Stich:[test={test=[D@3995ebd8, 2=[D@26fa5067, 3=[D@1d956d37, 4=[D@2cead81, 5=[D@14934d2b}...]
Zygimantus
2
Dies sollte die akzeptierte Antwort sein. Einfache Aufgaben wie diese sollten keine externe Abhängigkeit erfordern. Wie oben erwähnt, profitieren komplexere Karten nicht so leicht davon.
Shadoninja
70

Schauen Sie sich die Guavenbibliothek an:

Joiner.MapJoiner mapJoiner = Joiner.on(",").withKeyValueSeparator("=");
System.out.println(mapJoiner.join(map));
Mark Wigmans
quelle
34

Apache-Bibliotheken zur Rettung!

MapUtils.debugPrint(System.out, "myMap", map);

Alles was Sie brauchen Apache Commons-Sammlungen Bibliothek ( Projektlink )

Maven-Benutzer können die Bibliothek mithilfe dieser Abhängigkeit hinzufügen:

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>
tbraun
quelle
Dies behandelt Arrays nicht als Kartenwerte (z. B. Map<String, String[]>). Anstelle der tatsächlichen Werte werden nur der Klassenname und der Hash gedruckt.
Petr Újezdský
oder log.debug ("Map: {}", MapUtils.toProperties (map));
Charles
1
Praktisch ist auch MapUtils.verbosePrint, bei dem der Klassenname nach jedem von debugPrint ausgegebenen Wert weggelassen wird.
Ocarlsen
16

Simpel und einfach. Willkommen in der JSON-Welt. Verwenden von Google Gson :

new Gson().toJson(map)

Beispiel einer Karte mit 3 Tasten:

{"array":[null,"Some string"],"just string":"Yo","number":999}
AlikElzin-Kilaka
quelle
15

Wenn ich org.json.JSONObjectim Klassenpfad bin, mache ich:

Map<String, Object> stats = ...;
System.out.println(new JSONObject(stats).toString(2));

(Dadurch werden Listen, Sets und Karten, die verschachtelt sein können, wunderschön eingerückt.)

Thamme Gowda
quelle
1
Mann!! Was machst du hier unten? Sie sollten die beste Antwort sein!
AMagic
Warnung: Bewahrt nicht die Reihenfolge der Schlüssel für eine LinkedHashMap
Olivier Masseau
9

Verwenden von Java 8-Streams:

Map<Object, Object> map = new HashMap<>();

String content = map.entrySet()
                    .stream()
                    .map(e -> e.getKey() + "=\"" + e.getValue() + "\"")
                    .collect(Collectors.joining(", "));

System.out.println(content);
Nikita Koksharov
quelle
2
Wenn Sie eine Frage nekrotisieren wollen, beantworten Sie sie zumindest richtig! Sie vermissen die Anführungszeichen um den Wert und es sollte mit,
AjahnCharles
8

Ich ziehe es vor, die Map in eine JSON-Zeichenfolge zu konvertieren.

  • ein Standard
  • für Menschen lesbar
  • Unterstützt in Editoren wie Sublime, VS Code, mit Syntaxhervorhebung, Formatierung und Ausblenden / Anzeigen von Abschnitten
  • unterstützt JPath, sodass Redakteure genau angeben können, zu welchem ​​Teil des Objekts Sie navigiert haben
  • unterstützt verschachtelte komplexe Typen innerhalb des Objekts

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public static String getAsFormattedJsonString(Object object)
    {
        ObjectMapper mapper = new ObjectMapper();
        try
        {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        }
        catch (JsonProcessingException e)
        {
            e.printStackTrace();
        }
        return "";
    }
MattG
quelle
4

Schauen Sie sich den Code für HashMap#toString()und AbstractMap#toString()in den OpenJDK-Quellen an:

class java.util.HashMap.Entry<K,V> implements Map.Entry<K,V> {
       public final String toString() {
           return getKey() + "=" + getValue();
       }
   }
 class java.util.AbstractMap<K,V> {
     public String toString() {
         Iterator<Entry<K,V>> i = entrySet().iterator();
         if (! i.hasNext())
            return "{}";

        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key);
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(", ");
        }
    }
}

Wenn die Jungs von OpenJDK keinen eleganteren Weg gefunden haben, gibt es keinen :-)

parasietje
quelle
3

Sie sollten in der Lage sein, das zu tun, was Sie wollen, indem Sie Folgendes tun:

System.out.println(map) beispielsweise

Solange ALLE Ihre Objekte in der Karte die toStringMethode überschrieben haben, die Sie sehen würden:
{key1=value1, key2=value2}auf sinnvolle Weise

Wenn dies für Ihren Code gilt, ist das Überschreiben toStringeine gute Angewohnheit, und ich schlage vor, dass Sie sich stattdessen dafür entscheiden.

Für Ihr Beispiel, wo sich Ihre Objekte befinden String, sollten Sie ohne irgendetwas anderes in Ordnung sein.
Dh System.out.println(map)ohne zusätzlichen Code genau das drucken, was Sie brauchen

Cratylus
quelle
1
seine Schlüssel und Werte sind Zeichenketten; Ich denke, er hat die toString-Methode behandelt.
Tom
Sie haben Recht, aber vielleicht hat er ein triviales Beispiel kopiert, um seinen Standpunkt zu verdeutlichen. Aber ich aktualisiere die Antwort
Cratylus
Ja, ich hätte angeben sollen, dass meine Karte Map <String, String> ist. Ich habe aber auch angegeben, dass ich mehr Freiheit bei meinen Eingabewerten haben möchte, z. B. durch durch Kommas getrennte Listen innerhalb des Wertes eines Eintrags. Map.toString () reicht also nicht aus.
space_monkey
Die Schnittstelle java.util.Maphat keinen Vertrag bezüglich toString(), es liegt also an der tatsächlichen MapImplementierung, was System.out.println(map)-> PrintStream.println(map)-> String.valueOf(map)-> map.toString()verursachen wird. Es kommt vor, dass die häufig verwendete java.util.AbstractMapeine schöne Zeichenfolgendarstellung für bietet toString(). ... Andere MapImplementierungen können zurückgreifen Object.toString(), was zu weniger informativen Ergebnissen führt com.example.MyMap@4e8c0de.
Abdull
2
public void printMapV2 (Map <?, ?> map) {
    StringBuilder sb = new StringBuilder(128);
    sb.append("{");
    for (Map.Entry<?,?> entry : map.entrySet()) {
        if (sb.length()>1) {
            sb.append(", ");
        }
        sb.append(entry.getKey()).append("=").append(entry.getValue());
    }
    sb.append("}");
    System.out.println(sb);
}
Steine333
quelle
0

Ich denke, so etwas wäre sauberer und bietet Ihnen mehr Flexibilität beim Ausgabeformat (einfach Vorlage ändern):

    String template = "%s=\"%s\",";
    StringBuilder sb = new StringBuilder();
    for (Entry e : map.entrySet()) {
        sb.append(String.format(template, e.getKey(), e.getValue()));
    }
    if (sb.length() > 0) {
        sb.deleteCharAt(sb.length() - 1); // Ugly way to remove the last comma
    }
    return sb.toString();

Ich weiß, dass es hässlich ist, das letzte Komma entfernen zu müssen, aber ich denke, es ist sauberer als Alternativen wie die in dieser Lösung oder manuell mit einem Iterator.

Damen und Herren
quelle
0

Als schnelle und schmutzige Lösung, die die vorhandene Infrastruktur nutzt, können Sie Ihre uglyPrintedMapin eine einpacken java.util.HashMapund dann verwenden toString().

uglyPrintedMap.toString(); // ugly
System.out.println( uglyPrintedMap ); // prints in an ugly manner

new HashMap<Object, Object>(jobDataMap).toString(); // pretty
System.out.println( new HashMap<Object, Object>(uglyPrintedMap) ); // prints in a pretty manner
Abdull
quelle
0

Beantwortet nicht genau die Frage, aber es ist erwähnenswert, Lombodok @ToString Annotation . Wenn Sie mit @ToStringden key / valueKlassen Anmerkungen machen , gibt dies System.out.println(map)etwas Sinnvolles zurück.

Es funktioniert auch sehr gut mit Karten von Karten, zum Beispiel: Map<MyKeyClass, Map<String, MyValueClass>>wird gedruckt als

{MyKeyClass(properties...)={string1=MyValuesClass(properties...), string2=MyValuesCalss(properties...),..}, ... }

user1485864
quelle
0

String result = objectMapper.writeValueAsString(map) - so einfach!

Ergebnis:

{"2019-07-04T03:00":1,"2019-07-04T04:00":1,"2019-07-04T01:00":1,"2019-07-04T02:00":1,"2019-07-04T13:00":1,"2019-07-04T06:00":1 ...}

PS Fügen Sie Jackson JSON zu Ihrem Klassenpfad hinzu.

user2171669
quelle
0

Seit Java 8 gibt es eine einfache Möglichkeit, dies mit Lambda zu tun:

yourMap.keySet().forEach(key -> {
    Object obj = yourMap.get(key);
    System.out.println( obj);
}
Tomasz Stępnik
quelle