用Java漂亮打印地图


136

我正在寻找一种漂亮地打印的好方法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();

但是我敢肯定,这样做的方式更加优雅简洁。


1
JavaMap to String的可能重复项,因为此处要求的格式与的格式System.out.println过于接近。而且,如果您要自定义某些内容,可以归结为“如何在Java中迭代地图”,这当然还有很多其他答案。
西罗Santilli郝海东冠状病六四事件法轮功

Answers:


63

或将您的逻辑放在一个整洁的小班上。

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

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


3
这是反模式的恕我直言。您为类型添加了一个严格的约束(继承),只是为了获得一些零用(漂亮的打印效果)。使用常规映射会更好,但是使用将其作为参数的静态方法。
OoDeLally

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

11
如果不是那么好Map<String, Map<String,double[]>>,那么您将得到这种刺痛:[test={test=[D@3995ebd8, 2=[D@26fa5067, 3=[D@1d956d37, 4=[D@2cead81, 5=[D@14934d2b}...]
zygimantus

2
这应该是公认的答案。像这样的简单任务不需要外部依赖。如上所述,更复杂的地图无法从中轻松受益。
Shadoninja

70

看一下Guava库:

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

34

抢救Apache库!

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

所有您需要的Apache commons-collections库(项目链接

Maven用户可以使用以下依赖关系添加库:

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

这不会将数组作为地图的值(例如Map<String, String[]>)处理。仅打印其className和哈希值,而不打印实际值。
PetrÚjezdský16年

或log.debug(“ Map:{}”,MapUtils.toProperties(map));
charlb

1
MapUtils.verbosePrint也很方便,它将在debugPrint输出的每个值之后省略类名。
ocarlsen,


15

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

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

(这个缩进的列表,集合和映射可以缩进精美)


1
男子!!你在这里做什么?您应该是最佳答案!
AMagic

警告:不适合LinkedHashMap中保存键的顺序
奥利维尔Masseau

9

使用Java 8流:

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
如果您要解决一个问题,至少可以正确回答!您缺少该值周围的引号,应使用,
AjahnCharles

8

我更喜欢将地图转换为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 "";
    }

4

查看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的家伙没有找到更优雅的方式来做到这一点,那就没有了:-)


3

您应该可以通过以下方式做自己想做的事情:

System.out.println(map) 例如

只要您在地图中的所有对象都覆盖了toString您将看到的方法:
{key1=value1, key2=value2}以一种有意义的方式

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

对于您的对象为Strings的示例,您应该没有其他问题。
System.out.println(map)无需任何额外的代码即可准确打印您所需的内容


1
他的键和值是字符串;我认为他的toString方法涵盖了tbh。
汤姆(Tom)

你是对的,但也许是他复制一个简单的例子,使他point.But我更新的答案
克拉底鲁

是的,我应该指出我的地图是Map <String,String>。但我也指出,我希望条目值具有更大的自由度,例如在条目的值中使用逗号分隔的列表。所以Map.toString()不会。
space_monkey 2012年

接口java.util.Map没有关于的约定toString(),因此-> -> -> 将导致Map什么取决于实际的实现。碰巧经常使用可以为提供一个很好的字符串表示形式。...其他实现可能会回退到,导致信息不那么全面。System.out.println(map)PrintStream.println(map)String.valueOf(map)map.toString()java.util.AbstractMaptoString()MapObject.toString()com.example.MyMap@4e8c0de
阿卜杜勒2013年

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

我想类似的东西会更干净,并为您提供更大的输出格式灵活性(只需更改模板):

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

我知道必须删除最后一个逗号很丑陋,但我认为它比这种解决方案中的替代方法或手动使用迭代器的方法更干净。


0

作为利用现有基础架构的快速而肮脏的解决方案,您可以将其包装uglyPrintedMapjava.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

0

不能完全回答问题,但是值得一提的是Lombodok @ToString 批注。如果您有注释@ToStringkey / value类,然后做System.out.println(map)将返回有意义的事。

它也适用于地图地图,例如: Map<MyKeyClass, Map<String, MyValueClass>>将打印为

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


0

String result = objectMapper.writeValueAsString(map) -就这么简单!

结果:

{"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将Jackson JSON添加到您的类路径中。


0

从Java 8开始,使用Lambda可以轻松实现:

yourMap.keySet().forEach(key -> {
    Object obj = yourMap.get(key);
    System.out.println( obj);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.