Pretty-печать карты на 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();


но я уверен, что есть более элегантный и лаконичный способ сделать это.

623   14  

14 ответов:

или поместите свою логику в аккуратный маленький класс.

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

Примечание: Вы также можете поместить эту логику в метод утилит.

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

взгляните на библиотеку гуавы:

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

библиотеки Apache на помощь!

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

все, что вам нужно Apache commons-collections library ( ссылка на проект)

пользователи Maven могут добавить библиотеку, используя эту зависимость:

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

когда у меня есть org.json.JSONObject в classpath, я делаю:

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

(это красиво отступы, списки, наборы и карты, которые могут быть вложенными)

просто и легко. Добро пожаловать в мир JSON. Используя Gson от Google:

new Gson().toJson(map)

пример карты с 3 ключами:

{"array":[null,"Some string"],"just string":"Yo","number":999}

Я предпочитаю конвертировать карту в строку 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 "";
    }
    

посмотреть код 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 не нашли более элегантный способ сделать это, нет ни одного: -)

Использование 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);
}

вы должны быть в состоянии сделать то, что вы хотите делать:

пока все ваши объекты на карте имеют overiden toString способ вы увидите:
{key1=value1, key2=value2} в осмысленной манере

если это для вашего кода, то overiding toString - это хорошая привычка и я предлагаю вам пойти на это.

для вашего примера, где ваши объекты Strings Вы должны быть в порядке без чего-либо еще.
Т. е. System.out.println(map) будет печатать именно то, что вам нужно без какого-либо дополнительного кода

Я думаю, что-то вроде этого было бы чище, и предоставить вам больше гибкости с форматом вывода (просто изменить шаблон):

    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 the key / value классы, а затем делать System.out.println(map) вернет что-то значимое.

он также очень хорошо работает с картами карт, например: Map<MyKeyClass, Map<String, MyValueClass>> будет напечатано как

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

Comments

    Ничего не найдено.