web-dev-qa-db-fra.com

Pretty-print une carte en Java

Je cherche un moyen agréable d'imprimer joliment un Map.

map.toString() me donne: {key1=value1, key2=value2, key3=value3}

Je veux plus de liberté dans les valeurs d'entrée de ma carte et je cherche quelque chose qui ressemble à ceci: key1="value1", key2="value2", key3="value3"

J'ai écrit ce petit morceau de 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();

Mais je suis sûr qu’il existe un moyen plus élégant et concis de procéder.

114
space_monkey

Ou mettez votre logique dans une petite classe bien rangée.

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

    }
}

Usage:

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

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

Remarque: Vous pouvez également mettre cette logique dans une méthode utilitaire.

56
adarshr
Arrays.toString(map.entrySet().toArray())
270

Jetez un coup d'œil à la bibliothèque Guava:

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

Les bibliothèques Apache à la rescousse!

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

Tout ce dont vous avez besoin Apache commons-collections library ( lien de projet )

Les utilisateurs Maven peuvent ajouter la bibliothèque en utilisant cette dépendance:

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

Simple et facile. Bienvenue dans le monde JSON. Utilisation de Google Gson :

new Gson().toJson(map)

Exemple de carte avec 3 clés:

{"array":[null,"Some string"],"just string":"Yo","number":999}
10
AlikElzin-kilaka

Quand j'ai org.json.JSONObject dans le classpath, je fais:

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

(cela met magnifiquement en retrait des listes, des ensembles et des cartes qui peuvent être imbriquées)

10
Thamme Gowda

Je préfère convertir la carte en une chaîne JSON:

  • une référence 
  • lisible par l'homme
  • pris en charge dans les éditeurs tels que Sublime, VS Code, avec la syntaxe surlignage, formatage et masquage de section
  • prend en charge JPath afin que les éditeurs puissent signaler exactement quelle partie de l’objetvous avez navigué jusqu’à
  • prend en charge les types complexes imbriqués dans l'objet

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

Utilisation de 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);
5
Nikita Koksharov

Regardez le code pour HashMap#toString() et AbstractMap#toString() dans les sources 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(", ");
        }
    }
}

Donc si les gars d'OpenJDK n'ont pas trouvé de moyen plus élégant de le faire, il n'y en a pas :-)

4
parasietje
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);
}
2
stones333

Vous devriez pouvoir faire ce que vous voulez en faisant: 

System.out.println(map) par exemple 

Tant que TOUS vos objets sur la carte ont surchargé la méthode toString, vous verrez:
{key1=value1, key2=value2} d'une manière significative

Si ceci est pour votre code, alors toString est une bonne habitude et je vous suggère d’y aller plutôt. 

Pour votre exemple où vos objets sont Strings vous devriez aller sans rien d'autre.
C'est à dire. System.out.println(map) imprimerait exactement ce dont vous avez besoin sans code supplémentaire

1
Cratylus

Je suppose que quelque chose comme ceci serait plus propre et vous donnerait plus de flexibilité avec le format de sortie (changez simplement de modèle):

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

Je sais que devoir supprimer la dernière virgule est moche, mais je pense que c'est plus propre que des alternatives comme celle dans cette solution ou manuellement à l'aide d'un itérateur.

0
Sirs

En tant que solution rapide et optimisée exploitant l'infrastructure existante, vous pouvez envelopper votre uglyPrintedMap dans un Java.util.HashMap, puis utiliser 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
Abdull

String result = objectMapper.writeValueAsString(map) - aussi simple que cela!

Résultat:

{"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. Ajoutez Jackson JSON à votre chemin de classe.

0
user2171669

Ne répond pas exactement à la question, mais il convient de mentionner Lombodok @ToStringannotation . Si vous annotez avec @ToString les classes key / value, faire System.out.println(map) retournera quelque chose de significatif. 

Cela fonctionne aussi très bien avec les cartes-de-cartes, par exemple: Map<MyKeyClass, Map<String, MyValueClass>> sera imprimé comme

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

0
user1485864