Хорошая печать коллекций Java (toString не возвращает симпатичный вывод)

211

Я хочу напечатать Stack<Integer>объект так же хорошо, как это делает отладчик Eclipse (то есть [1,2,3...]), но печать с ним out = "output:" + stackне возвращает этот хороший результат.

Просто чтобы уточнить, я говорю о встроенной коллекции Java, поэтому я не могу переопределить ее toString().

Как я могу получить хорошую версию стека для печати?

Элазар Лейбович
источник
7
По крайней мере, в Java 7 AbstractCollection@toString(и, следовательно String + Stack) уже печатает его так, как вы этого хотите.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

317

Вы можете преобразовать его в массив, а затем распечатать его с помощью Arrays.toString(Object[]):

System.out.println(Arrays.toString(stack.toArray()));
Зак Лэнгли
источник
11
Мне это нравится. Просто, чисто. Честно говоря, коллекциям тоже нужен метод toString, но это тоже работает.
Тови7
1
@ Tovi7 Вероятно, это не так, потому что большинство коллекций OOTB уже предоставляют читаемые toString (), а массивы - нет.
Макс Нанаси
@Boosha также требуется O (n) время для преобразования стека в строку и O (n) время для вывода строки в консоль
Зак Лэнгли,
stack.toArray()может быть очень дорогим, процессор, время и память мудры. Решение, которое перебирает исходную коллекцию / повторяемость, вероятно, будет менее ресурсоемким.
АликЭльзин-килака
52
String.join(",", yourIterable);

(Java 8)

user1016765
источник
12
yourIterable должен быть Iterable <? расширяет CharSequence>
Натан
3
String.join (",", yourCollection.stream (). Map (o -> o.toString ()). Collect (Collectors.toList ()))
user1016765
@ user1016765 yourCollection.stream().map( o -> o.toString() ).collect( joining(",") ))лучше, потому что вы читаете его слева направо, вам не нужно оглядываться назад, чтобы вычислить в
уме,
18

С помощью потоков и сборщиков java 8 это можно сделать легко:

String format(Collection<?> c) {
  String s = c.stream().map(Object::toString).collect(Collectors.joining(","));
  return String.format("[%s]", s);
}

сначала мы используем mapс, Object::toStringчтобы создать, Collection<String>а затем используем объединяющий коллектор, чтобы соединить каждый элемент в коллекции с ,разделителем.

bsmk
источник
22
Мне пришлось сдерживаться, чтобы не убрать слово «легко» из ответа ;-) Collections.toString(stack)было бы легко.
FrVaBe
Почему вызов String.format ()? Это просто чтобы получить квадратные скобки?
Jolta
18

Класс MapUtils, предлагаемый проектом Apache Commons, предлагает MapUtils.debugPrintметод, который будет красиво печатать вашу карту.

tlavarea
источник
Не то, что я знаю о. Я не очень знаком с библиотекой Гуавы, но я не удивлюсь, если таковая будет.
tlavarea
В этом нет необходимости, по крайней мере, в Java 6, потому что AbstractMap # toString уже делает это. Вопрос только по карте: stackoverflow.com/questions/2828252/map-to-string-in-java
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
12

System.out.println (Коллекция c) уже печатает любой тип коллекции в удобочитаемом формате. Только если коллекция содержит определенные пользователем объекты, вам нужно реализовать toString () в определенном пользователем классе для отображения содержимого.

Шекхар
источник
12

Реализуйте toString () в классе.

Я рекомендую Apache Commons ToStringBuilder, чтобы сделать это проще. При этом вам просто нужно написать такой метод:

public String toString() {
     return new ToStringBuilder(this).
       append("name", name).
       append("age", age).
       toString(); 
}

Для того, чтобы получить такой вывод:

Человек @ 7f54 [имя = Стивен, возраст = 29]

Существует также рефлексивная реализация .

Chinnery
источник
ToStringBuilder обычно больше подходит для bean-объектов и объектов, несущих информацию, в меньшей степени для сложных структур данных. Если объект стека не печатает все сохраненные элементы, это не поможет.
Uri
2
использование отражений ToStringBuilder, HashCodeBuilder и EqualsBuilder крайне неэффективно. Хотя результаты в порядке, эти классы едва ли достигают максимальных результатов недели ...
Ян Хруби,
2
Вопрос явно говорит о том, что класс является встроенной коллекцией, поэтому toString () нельзя изменить.
Расмус Кай
9

Я согласен с приведенными выше комментариями о переопределении toString()ваших собственных классов (и об максимально возможной автоматизации этого процесса).

Для классов, которые вы не определили, вы можете написать ToStringHelperкласс с перегруженным методом для каждого библиотечного класса, который вы хотите обработать по своему вкусу:

public class ToStringHelper {
    //... instance configuration here (e.g. punctuation, etc.)
    public toString(List m) {
        // presentation of List content to your liking
    }
    public toString(Map m) {
        // presentation of Map content to your liking
    }
    public toString(Set m) {
        // presentation of Set content to your liking
    }
    //... etc.
}

РЕДАКТИРОВАТЬ: Отвечая на комментарий xukxpvfzflbbld, вот возможная реализация для случаев, упомянутых ранее.

package com.so.demos;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class ToStringHelper {

    private String separator;
    private String arrow;

    public ToStringHelper(String separator, String arrow) {
        this.separator = separator;
        this.arrow = arrow;
    }

   public String toString(List<?> l) {
        StringBuilder sb = new StringBuilder("(");
        String sep = "";
        for (Object object : l) {
            sb.append(sep).append(object.toString());
            sep = separator;
        }
        return sb.append(")").toString();
    }

    public String toString(Map<?,?> m) {
        StringBuilder sb = new StringBuilder("[");
        String sep = "";
        for (Object object : m.keySet()) {
            sb.append(sep)
              .append(object.toString())
              .append(arrow)
              .append(m.get(object).toString());
            sep = separator;
        }
        return sb.append("]").toString();
    }

    public String toString(Set<?> s) {
        StringBuilder sb = new StringBuilder("{");
        String sep = "";
        for (Object object : s) {
            sb.append(sep).append(object.toString());
            sep = separator;
        }
        return sb.append("}").toString();
    }

}

Это не полномасштабная реализация, а просто стартер.

joel.neely
источник
7

Вы можете использовать класс "Objects" из JAVA (который доступен с 1.7)

Collection<String> myCollection = Arrays.asList("1273","123","876","897");
Objects.toString(myCollection);

Выход: 1273, 123, 876, 897

Другая возможность - использовать класс «MoreObjects» из Google Guave , который предоставляет множество полезных вспомогательных функций:

MoreObjects.toStringHelper(this).add("NameOfYourObject", myCollection).toString());

Вывод: NameOfYourObject = [1273, 123, 876, 897]

Guava Docs

Chisey88
источник
1
Objects.toString()просто призывает toString()коллекцию. В вашем примере это работает, потому что, предположительно, toString()в коллекции на основе массива получается красиво печатать.
GuyPaddock
3

С Apache Commons 3 вы хотите позвонить

StringUtils.join(myCollection, ",")
JRA_TLL
источник
3

В Java8

//will prints each element line by line
stack.forEach(System.out::println);

или

//to print with commas
stack.forEach(
    (ele) -> {
        System.out.print(ele + ",");
    }
);
ЙОГ
источник
1

Просто изменил предыдущий пример для печати четной коллекции, содержащей определенные пользователем объекты.

public class ToStringHelper {

    private  static String separator = "\n";

    public ToStringHelper(String seperator) {
        super();
        ToStringHelper.separator = seperator;

    }

    public  static String toString(List<?> l) {
        StringBuilder sb = new StringBuilder();
        String sep = "";
        for (Object object : l) {
            String v = ToStringBuilder.reflectionToString(object);
            int start = v.indexOf("[");
            int end = v.indexOf("]");
            String st =  v.substring(start,end+1);
            sb.append(sep).append(st);
            sep = separator;
        }
        return sb.toString();
    }

    public static String toString(Map<?,?> m) {
        StringBuilder sb = new StringBuilder();
        String sep = "";
        for (Object object : m.keySet()) {
            String v = ToStringBuilder.reflectionToString(m.get(object));
            int start = v.indexOf("[");
            int end = v.indexOf("]");
            String st =  v.substring(start,end+1);
            sb.append(sep).append(st);
            sep = separator;
        }
        return sb.toString();
    }

    public static String toString(Set<?> s) {
        StringBuilder sb = new StringBuilder();
        String sep = "";
        for (Object object : s) {
            String v = ToStringBuilder.reflectionToString(object);
            int start = v.indexOf("[");
            int end = v.indexOf("]");
            String st =  v.substring(start,end+1);
            sb.append(sep).append(st);
            sep = separator;
        }
        return sb.toString();
    }

    public static void print(List<?> l) {
        System.out.println(toString(l));    
    }
    public static void print(Map<?,?> m) {
        System.out.println(toString(m));    
    }
    public static void print(Set<?> s) {
        System.out.println(toString(s));    
    }

}
Шекхар
источник
1

toString()в наши дни большинство коллекций имеют полезную информацию в Java (Java7 / 8). Поэтому нет необходимости выполнять потоковые операции для объединения того, что вам нужно, просто переопределите toStringваш класс значений в коллекции, и вы получите то, что вам нужно.

и AbstractMap, и AbstractCollection реализуют toString (), вызывая toString для каждого элемента.

ниже тестовый класс, чтобы показать поведение.

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class ToString {
  static class Foo {
    int i;
    public Foo(int i) { this.i=i; }
    @Override
    public String toString() {
        return "{ i: " + i + " }";
    }
  }
  public static void main(String[] args) {
    List<Foo> foo = new ArrayList<>();
    foo.add(new Foo(10));
    foo.add(new Foo(12));
    foo.add(new Foo(13));
    foo.add(new Foo(14));
    System.out.println(foo.toString());
    // prints: [{ i: 10 }, { i: 12 }, { i: 13 }, { i: 14 }]

    Map<Integer, Foo> foo2 = new HashMap<>();
    foo2.put(10, new Foo(10));
    foo2.put(12, new Foo(12));
    foo2.put(13, new Foo(13));
    foo2.put(14, new Foo(14));
    System.out.println(foo2.toString());
    // prints: {10={ i: 10 }, 12={ i: 12 }, 13={ i: 13 }, 14={ i: 14 }}
  }
}
Alex
источник
1

JSON

Альтернативным решением может быть преобразование вашей коллекции в формат JSON и печать Json-String. Преимущество - хорошо отформатированная и читаемая объектная строка без необходимости реализации toString().

Пример использования Google Gson :

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

...

    printJsonString(stack);

...
public static void printJsonString(Object o) {
    GsonBuilder gsonBuilder = new GsonBuilder();
    /*
     * Some options for GsonBuilder like setting dateformat or pretty printing
     */
    Gson gson = gsonBuilder.create();
    String json= gson.toJson(o);
    System.out.println(json);
}
tobsob
источник
0

Если это ваш собственный класс коллекции, а не встроенный, вам необходимо переопределить его метод toString. Eclipse вызывает эту функцию для любых объектов, для которых она не имеет аппаратного форматирования.

Uri
источник
И как eclipse форматирует эти классы с помощью проводного форматирования? Это то, что я ищу.
Элазар Лейбович
0

Будьте осторожны при вызове Sop на Collection, он может выдать ConcurrentModificationException. Потому что внутренний toStringметод каждой коллекции внутренне вызывает Iteratorколлекцию.

Harneet
источник
0

Должно работать на любую коллекцию, кроме Map, но ее также легко поддерживать. Измените код, чтобы передать эти 3 символа в качестве аргументов, если это необходимо.

static <T> String seqToString(Iterable<T> items) {
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    boolean needSeparator = false;
    for (T x : items) {
        if (needSeparator)
            sb.append(' ');
        sb.append(x.toString());
        needSeparator = true;
    }
    sb.append(']');
    return sb.toString();
}
Отображаемое имя
источник
0

Вы можете попробовать использовать

org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(yourCollection);
user1016765
источник
0

Есть два способа упростить вашу работу. 1. импортировать библиотеку Gson. 2. использовать Ломбок.

Оба они помогают вам создать String из экземпляра объекта. Gson проанализирует ваш объект, lombok переопределит ваш метод класса объекта toString.

Я положил пример о Gson prettyPrint, я создаю вспомогательный класс для печати объекта и коллекции объектов. Если вы используете lombok, вы можете пометить свой класс как @ToString и напечатать свой объект напрямую.

@Scope(value = "prototype")
@Component
public class DebugPrint<T> {
   public String PrettyPrint(T obj){
      Gson gson = new GsonBuilder().setPrettyPrinting().create();
      return gson.toJson(obj);
   }
   public String PrettyPrint(Collection<T> list){
      Gson gson = new GsonBuilder().setPrettyPrinting().create();
      return list.stream().map(gson::toJson).collect(Collectors.joining(","));
   }

}

Донгкай Хуан
источник