用 Java 漂亮地打印地图

我正在寻找一个漂亮的方式打印 Map

map.toString()给我的是: {key1=value1, key2=value2, key3=value3}

我希望在我的地图入口值更自由,我正在寻找更像这样的东西: key1="value1", key2="value2", key3="value3"

我写了这段代码:

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

但我相信有一个更优雅和简洁的方式来做到这一点。

180331 次浏览

你应该能够做你想做的事情:

例如 System.out.println(map)

只要地图上的所有对象都覆盖了 toString方法,你就会看到:
以一种有意义的方式

如果这是为了您的代码,那么覆盖 toString是一个好习惯,我建议您改为这样做。

对于你的例子,你的对象是 String你应该没有任何其他罚款。
也就是说,System.out.println(map)可以准确地打印出你需要的内容,而不需要任何额外的代码

或者把你的逻辑放进一个整洁的小班。

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


}
}

用法:

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


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

注意: 您也可以将该逻辑放入实用程序方法中。

我猜想这样的东西会更干净,并为您提供更多的灵活性与输出格式(简单地改变模板) :

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

我知道必须删除最后一个逗号很难看,但我认为它比 在这个溶液中或手动使用迭代器等替代方案更干净。

查看 OpenJDK 源代码中 HashMap#toString()AbstractMap#toString()的代码:

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

因此,如果 OpenJDK 的工作人员没有找到一种更优雅的方法来做到这一点,那么就没有了: -)

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

作为一个利用现有基础设施的快速而肮脏的解决方案,您可以将 uglyPrintedMap封装成 java.util.HashMap,然后使用 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

看看番石榴图书馆:

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

阿帕奇库拯救世界!

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

所有您需要的 Apache commons-Collection 库(项目连结)

Maven 用户可以使用这个依赖项添加库:

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

当我在类路径中有 org.json.JSONObject时,我会:

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

(这美丽的缩进列表,集合和地图,可以嵌套)

简单易行。欢迎来到 JSON 世界。使用 谷歌的 Gson:

new Gson().toJson(map)

带有3个键的地图示例:

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

使用 Java8流:

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


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


System.out.println(content);

我更喜欢将映射转换为 JSON 字符串:

  • 一个标准
  • 人类可读性
  • 在编辑器中支持,如 Sublime,VS Code,带有语法 突出显示、格式化和节隐藏/显示
  • 支持 JPath,这样编辑器可以准确地报告对象的哪一部分 你已经导航到了
  • 支持对象内嵌套的复杂类型

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

虽然没有准确回答这个问题,但值得一提的是 Lombodok @ToString 注释。如果您使用 @ToString注释 key / value类,那么执行 System.out.println(map)将返回一些有意义的内容。

它还可以很好地使用地图中的地图,例如: Map<MyKeyClass, Map<String, MyValueClass>>将打印为

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

就这么简单!

结果:

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

附注: 将 Jackson JSON 添加到您的类路径。

因为 java 8有一个简单的方法来实现 Lambda:

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