Pretty-imprimer une carte en Java
Je cherche un bon moyen d'imprimer un Map
.
map.toString()
donne-moi: {key1=value1, key2=value2, key3=value3}
Je veux plus de liberté dans mes valeurs d'entrée de carte et je cherche quelque chose de plus comme 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 une façon plus élégante et concise de le faire.
14 answers
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();
}
}
Utilisation:
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.
Arrays.toString(map.entrySet().toArray())
Jetez un oeil à la bibliothèque de Goyave:
Joiner.MapJoiner mapJoiner = Joiner.on(",").withKeyValueSeparator("=");
System.out.println(mapJoiner.join(map));
Les bibliothèques Apache à la rescousse!
MapUtils.debugPrint(System.out, "myMap", map);
Tout ce dont vous avez besoin Apache commons-collections library (project link )
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>
Quand j'ai org.json.JSONObject
dans le classpath, je n':
Map<String, Object> stats = ...;
System.out.println(new JSONObject(stats).toString(2));
(cela indente magnifiquement les listes, les ensembles et les cartes qui peuvent être imbriqués)
Simple et facile. Bienvenue dans le monde JSON. Utilisation de Gson de Google :
new Gson().toJson(map)
Exemple de carte avec 3 touches:
{"array":[null,"Some string"],"just string":"Yo","number":999}
Je préfère convertir la carte en une chaîne JSON c'est:
- une norme
- lisible par l'homme
- pris en charge dans des éditeurs comme Sublime, VS Code, avec syntaxe mise en surbrillance, mise en forme et section masquer/afficher
- prend en charge JPath afin que les éditeurs puissent signaler exactement quelle partie de l'objet vous avez navigué vers
-
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 ""; }
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: -)
Utilisation des flux 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);
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);
}
Vous devriez pouvoir faire ce que vous voulez en faisant:
System.out.println(map)
par exemple
Tant que TOUS vos objets de la carte ont dépassé la méthode toString
que vous verriez:{key1=value1, key2=value2}
de manière significative
Si c'est pour votre code, alors overiding toString
est une bonne habitude et je vous suggère d'y aller à la place.
Pour votre exemple où vos objets sont String
s, vous devriez aller bien sans rien d'autre.
C'est-à-dire que System.out.println(map)
imprimerait exactement ce dont vous avez besoin sans aucun code supplémentaire
Je suppose que quelque chose comme ça serait plus propre et vous offrirait 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 en utilisant un itérateur.
En tant que solution rapide et sale tirant parti de 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
Ne répond pas exactement à la question, mais il convient de mentionner Lombodok @ToString
annotation . Si vous annotez avec @ToString
les classes key / value
, alors faire System.out.println(map)
retournera quelque chose de significatif.
, Il fonctionne aussi très bien avec des cartes de cartes, par exemple:
Map<MyKeyClass, Map<String, MyValueClass>>
sera imprimé comme
{MyKeyClass(properties...)={string1=MyValuesClass(properties...), string2=MyValuesCalss(properties...),..},
...
}