Печать Java-коллекций красиво (toString не возвращает довольно вывода)

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

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

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

17 ответов


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

System.out.println(Arrays.toString(stack.toArray()));

String.join(",", yourIterable);

(Java 8)


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


С потоками 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> а затем используйте joining collector, чтобы присоединиться к каждому элементу в коллекции с , в качестве разделителя.


реализовать toString () в классе.

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

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

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

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

также светоотражающие реализации.


Я согласен с приведенными выше комментариями о переопределении 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.
}

EDIT: отвечая на комментарий 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();
    }

}

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


гуава выглядит как хороший вариант:

Iterables.toString(myIterable)


можно использовать класс "объекты" из 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


В Java8

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

или

//to print with commas
stack.forEach(
    (ele)->{
               System.out.print(ele+",");
           }
);

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

StringUtils.join(myCollection, ",")

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

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

}

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


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


должны работать для любой коллекция за исключением 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();
}

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

org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(yourCollection);

большинство коллекций полезным 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 }}
  }
}