[java] Pretty-print a Map in Java

I am looking for a nice way to pretty-print a Map.

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

I want more freedom in my map entry values and am looking for something more like this: key1="value1", key2="value2", key3="value3"

I wrote this little piece of code:

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

But I am sure there is a more elegant and concise way to do this.

This question is related to java dictionary pretty-print

The answer is


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

When I have org.json.JSONObject in the classpath, I do:

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

(this beautifully indents lists, sets and maps which may be nested)


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

Look at the code for HashMap#toString() and AbstractMap#toString() in the OpenJDK sources:

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

So if the guys from OpenJDK did not find a more elegant way to do this, there is none :-)


You should be able to do what you want by doing:

System.out.println(map) for example

As long as ALL your objects in the map have overiden the toString method you would see:
{key1=value1, key2=value2} in a meaningfull manner

If this is for your code, then overiding toString is a good habit and I suggest you go for that instead.

For your example where your objects are Strings you should be fine without anything else.
I.e. System.out.println(map) would print exactly what you need without any extra code


Arrays.toString(map.entrySet().toArray())

Does not answer exactly the question, but it is worth mentioning Lombodok @ToString annotation. If you annotate with @ToString the key / value classes, then doing System.out.println(map) will return something meaningful.

It also works very well with maps-of-maps, for example: Map<MyKeyClass, Map<String, MyValueClass>> will be printed as

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


I guess something like this would be cleaner, and provide you with more flexibility with the output format (simply change template):

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

I know having to remove the last comma is ugly, but I think it's cleaner than alternatives like the one in this solution or manually using an iterator.


Simple and easy. Welcome to the JSON world. Using Google's Gson:

new Gson().toJson(map)

Example of map with 3 keys:

{"array":[null,"Some string"],"just string":"Yo","number":999}

String result = objectMapper.writeValueAsString(map) - as simple as this!

Result:

{"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 ...}

P.S. add Jackson JSON to your classpath.


Since java 8 there is easy way to do it with Lambda:

yourMap.keySet().forEach(key -> {
    Object obj = yourMap.get(key);
    System.out.println( obj);
}

I prefer to convert the map to a JSON string it is:

  • a standard
  • human readable
  • supported in editors like Sublime, VS Code, with syntax highlighting, formatting and section hide/show
  • supports JPath so editors can report exactly which part of the object you have navigated to
  • supports nested complex types within the object

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

Apache libraries to the rescue!

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

All you need Apache commons-collections library (project link)

Maven users can add the library using this dependency:

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

Have a look at the Guava library:

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

As a quick and dirty solution leveraging existing infrastructure, you can wrap your uglyPrintedMap into a java.util.HashMap, then use 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

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to dictionary

JS map return object python JSON object must be str, bytes or bytearray, not 'dict Python update a key in dict if it doesn't exist How to update the value of a key in a dictionary in Python? How to map an array of objects in React C# Dictionary get item by index Are dictionaries ordered in Python 3.6+? Split / Explode a column of dictionaries into separate columns with pandas Writing a dictionary to a text file? enumerate() for dictionary in python

Examples related to pretty-print

Print a list of space-separated elements in Python 3 Printing out a linked list using toString How can I pretty-print JSON using Go? JSON.stringify output to div in pretty print way Convert JSON String to Pretty Print JSON output using Jackson How to prettyprint a JSON file? Pretty-print a Map in Java Pretty-Print JSON Data to a File using Python How do I pretty-print existing JSON data with Java? Pretty-Printing JSON with PHP