Друк Java-колекцій чудово (toString не повертає гарний вихід)


211

Я хочу надрукувати Stack<Integer>об'єкт так само добре, як і налагоджувач Eclipse (тобто [1,2,3...]), але друк з ним out = "output:" + stackне повертає цього приємного результату.

Просто для уточнення, я говорю про вбудовану колекцію Java, тому я не можу її замінити toString().

Як я можу отримати приємну версію для друку стека?


7
Принаймні, як у Java 7, AbstractCollection@toString(і таким чином String + Stack) вже друкує його так, як вам хочеться.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Відповіді:


317

Ви можете перетворити його в масив, а потім роздрукувати його за допомогою Arrays.toString(Object[]):

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

11
Мені це подобається. Простий, чистий. Якщо чесно, то колекціям також потрібен метод toString, але це також працює.
Tovi7

1
@ Tovi7 Це, мабуть, не тому, що більшість колекцій OOTB вже забезпечують читати ToString () s, тоді як масиви цього не роблять.
Макс Нанасі

@Boosha також потрібно O (n) час для перетворення стека в рядок і O (n) час для друку рядка на консолі
Zach Langley

stack.toArray()може бути дуже дорогим, процесор, час і пам'ять. Рішення, яке повторює над оригінальною колекцією / ітерабельним, ймовірно, буде менш затребуваним.
АлікЕльзін-кілака

52
String.join(",", yourIterable);

(Java 8)


12
yourIterable повинен бути Iterable <? продовжує CharSequence>
Натан

3
String.join (",", yourCollection.stream (). Map (o -> o.toString ()). Collection (Collectors.toList ()))
user1016765

@ user1016765 yourCollection.stream().map( o -> o.toString() ).collect( joining(",") ))краще, тому що ви читаєте його зліва направо, вам не потрібно оглядатись спереду, щоб обчислити у своєму мозку, що робиться з проміжним списком
cdalxndr

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>а потім використовувати з'єднує колектор приєднатися кожен елемент в зборі з в ,якості роздільника.


22
Мені довелося стримуватися, щоб не видаляти слово "легко" з відповіді ;-) Collections.toString(stack)було б легко.
FrVaBe

Чому дзвінок на String.format ()? Це просто дістати квадратні дужки?
Жолта

18

Клас MapUtils, запропонований проектом Apache Commons, пропонує MapUtils.debugPrintметод, який дозволить добре роздрукувати вашу карту.


Не те, що я знаю. Я не дуже знайомий з бібліотекою Guava, але не здивувався б, якби був.
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]

Існує також рефлексивна реалізація .


ToStringBuilder зазвичай більше застосовується для бобів та об'єктів, які несуть інформацію, рідше для складних структур даних. Якщо об’єкт стеку не надрукує всі збережені елементи, це не допоможе.
Урі

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.
}

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

}

Це не повномасштабна реалізація, а лише запуск.


7

Ви можете використовувати клас "Об'єкти" від 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


1
Objects.toString()просто дзвонить toString()на колекцію. У вашому прикладі це працює, тому що, мабуть, toString()на колекції, підтримуваній масивом, трапляється гарно друкувати.
GuyPaddock

3

За допомогою Apache Commons 3 ви хочете зателефонувати

StringUtils.join(myCollection, ",")

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

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

0

Якщо це ваш власний клас колекції, а не вбудований, вам потрібно перекрити його метод toString. Eclipse викликає цю функцію для будь-яких об'єктів, для яких у неї немає жорсткого проводового форматування.


І як формується затемнення цих класів у форматі проводів? Це те, що я шукаю.
Елазар Лейбович

0

Будьте обережні, зателефонувавши Sop on Collection, це може кинути ConcurrentModificationвиняток. Тому що внутрішньо toStringметод кожної колекції внутрішньо викликає Iteratorколекцію.


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

Є два способи спростити роботу. 1. імпортувати бібліотеку Gson. 2. користуватися Ломбоком.

Обидва вони допомагають вам створити String з об’єкта об'єкта. Gson розбере ваш об'єкт, lombok замінить ваш клас об'єкт методомString.

Я ставлю приклад про Gson prettyPrint, створюю helper class для друку об'єктів та колекції об'єктів. Якщо ви використовуєте 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(","));
   }

}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.