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.


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.


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())

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

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>

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}

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.)


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

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

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 :-)


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


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

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.


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

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...),..}, ... }


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.


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);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.