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
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 String
s 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:
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
Source: Stackoverflow.com