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でマップを反復する方法」に要約され、確かに他の多くの答えがあります。
Ciro Santilli郝海东冠状病六四事件法轮功

回答:


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
これはアンチパターンimhoです。タイプに強力な制約(継承)を追加します。通常のマップを使用した方がよいでしょうが、それを引数として受け取る静的メソッドを使用します。
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

グアバ図書館を見てください:

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のキーの順序は保持されません
Olivier

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

コードを見てみましょうHashMap#toString()AbstractMap#toString()OpenJDKのソースで:

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メソッドをカバーしたと思います。
トム

あなたは正しいですが、おそらく彼はpoint.But I更新の答えを作るために簡単な例をコピーした
クラテュロス

はい、マップがMap <String、String>であることを示す必要がありました。しかし、エントリの値をより自由にしたいことも示しました。たとえば、エントリの値にカンマ区切りのリストを含めることができます。したがって、Map.toString()は機能しません。
space_monkey

インターフェース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
Abdull 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 アノテーションに言及する価値はあります。クラスに注釈を付けると@ToString、意味のあるものが返されます。key / valueSystem.out.println(map)

また、maps-of-mapsとの連携も良好です。たとえば、次の 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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.