簡體   English   中英

用 Java 漂亮地打印地圖

[英]Pretty-print a Map in 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();

但我相信有一種更優雅、更簡潔的方法來做到這一點。

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

看看番石榴圖書館:

Joiner.MapJoiner mapJoiner = Joiner.on(",").withKeyValueSeparator("=");
System.out.println(mapJoiner.join(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));

注意:您也可以將該邏輯放入實用程序方法中。

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>

當我在類路徑中有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}

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

我更喜歡將地圖轉換為 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 ""; }

查看 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 的人沒有找到更優雅的方法來做到這一點,那就沒有了 :-)

您應該能夠通過執行以下操作來做您想做的事:

System.out.println(map)為例

只要地圖中的所有對象都覆蓋了toString方法,您就會看到:
{key1=value1, key2=value2}以一種有意義的方式

如果這是為了您的代碼,那么覆蓋toString是一個好習慣,我建議您改用它。

對於您的對象是String的示例,您應該沒有其他任何事情。
System.out.println(map)無需任何額外代碼即可准確打印您需要的內容

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

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 添加到您的類路徑中。

我想這樣的事情會更清晰,並為您提供更大的輸出格式靈活性(只需更改模板):

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

我知道必須刪除最后一個逗號是丑陋的,但我認為它比這個解決方案中的替代方案或手動使用迭代器更干凈。

作為利用現有基礎設施的快速而骯臟的解決方案,您可以將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

不能准確回答問題,但值得一提的是 Lombodok @ToString注釋 如果您使用@ToString注釋key / value類,那么執行System.out.println(map)將返回一些有意義的東西。

它也適用於地圖的地圖,例如: Map<MyKeyClass, Map<String, MyValueClass>>將打印為

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

從 java 8 開始,使用 Lambda 可以很容易地做到這一點:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM