Pretty-print a Map in Java

JavaDictionaryPretty Print

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

Have a look at the Guava library:

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

Solution 3 - Java

Or put your logic into a tidy little class.

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

    }
}

Usage:

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

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

Note: You can also put that logic into a utility method.

Solution 4 - Java

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>
        

Solution 5 - Java

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)

Solution 6 - Java

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}

Solution 7 - Java

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

Solution 8 - Java

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

Solution 9 - Java

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

Solution 10 - Java

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

Solution 11 - Java

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

Solution 12 - Java

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.

Solution 13 - Java

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

Solution 14 - Java

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.

Solution 15 - Java

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

Solution 16 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionspace_monkeyView Question on Stackoverflow
Solution 1 - JavaArkadiusz CieślińskiView Answer on Stackoverflow
Solution 2 - JavaMark WigmansView Answer on Stackoverflow
Solution 3 - JavaadarshrView Answer on Stackoverflow
Solution 4 - JavatbraunView Answer on Stackoverflow
Solution 5 - JavaThamme GowdaView Answer on Stackoverflow
Solution 6 - JavaAlikElzin-kilakaView Answer on Stackoverflow
Solution 7 - JavaNikita KoksharovView Answer on Stackoverflow
Solution 8 - JavaMattGView Answer on Stackoverflow
Solution 9 - JavaparasietjeView Answer on Stackoverflow
Solution 10 - JavaCratylusView Answer on Stackoverflow
Solution 11 - Javastones333View Answer on Stackoverflow
Solution 12 - Javauser2171669View Answer on Stackoverflow
Solution 13 - JavaTomasz StępnikView Answer on Stackoverflow
Solution 14 - JavaSirsView Answer on Stackoverflow
Solution 15 - JavaAbdullView Answer on Stackoverflow
Solution 16 - Javauser1485864View Answer on Stackoverflow