234

I wish to print a Stack<Integer> object as nicely as the Eclipse debugger does (i.e. [1,2,3...]) but printing it with out = "output:" + stack doesn't return this nice result.

Just to clarify, I'm talking about Java's built-in collection so I can't override its toString().

How can I get a nice printable version of the stack?

Nathan
  • 8,093
  • 8
  • 50
  • 76
Elazar Leibovich
  • 32,750
  • 33
  • 122
  • 169

20 Answers20

345

You could convert it to an array and then print that out with Arrays.toString(Object[]):

System.out.println(Arrays.toString(stack.toArray()));
Zach Langley
  • 6,776
  • 1
  • 26
  • 25
  • 12
    I like it. Simple, clean. To be honest Collections needs a toString method too, but this works also. – Tovi7 Aug 03 '11 at 13:43
  • 1
    @Tovi7 It probably doesn't because most OOTB Collections already provide readable toString()s, whereas arrays don't. – Max Nanasy Jan 16 '13 at 17:56
  • @Boosha it also takes O(n) time to convert the stack to a string and O(n) time to print the string to the console – Zach Langley May 29 '15 at 15:27
  • 2
    `stack.toArray()` might be very expensive, cpu, time and memory wise. a Solution that iterates over the original collection/iterable would probably be less resource consuming. – AlikElzin-kilaka Feb 14 '19 at 10:24
67
String.join(",", yourIterable);

(Java 8)

user1016765
  • 2,935
  • 2
  • 32
  • 48
  • 13
    yourIterable has to be Iterable extends CharSequence> – Nathan Sep 11 '15 at 18:12
  • 4
    String.join(",", yourCollection.stream().map(o -> o.toString()).collect(Collectors.toList())) – user1016765 Jun 09 '16 at 16:17
  • 2
    @user1016765 `yourCollection.stream().map( o -> o.toString() ).collect( joining(",") ))` is better cos you read it from left to right, you don't need to look back at the front to compute in your brain what is done with the intermediate list – cdalxndr Apr 29 '20 at 18:16
19

With java 8 streams and collectors it can be done easily:

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

first we use map with Object::toString to create Collection<String> and then use joining collector to join every item in collection with , as delimiter.

bsmk
  • 1,307
  • 1
  • 14
  • 26
  • 25
    I had to hold back not to remove the word 'easily' from the answer ;-) `Collections.toString(stack)` would be easy. – FrVaBe Oct 15 '14 at 07:54
  • Why the call to String.format()? Is it just to get the square brackets? – Jolta Jun 13 '17 at 13:04
18

The MapUtils class offered by the Apache Commons project offers a MapUtils.debugPrint method which will pretty print your map.

Aniket Kulkarni
  • 12,825
  • 9
  • 67
  • 90
tlavarea
  • 603
  • 8
  • 14
  • 1
    Not that I know of. I'm not terribly familiar with the Guava library but I wouldn't be surprised if there was. – tlavarea Jan 18 '12 at 21:15
  • No need for this, at least in Java 6, because [AbstractMap#toString](http://docs.oracle.com/javase/6/docs/api/java/util/AbstractMap.html#toString%28%29) does it already. Map only question: http://stackoverflow.com/questions/2828252/map-to-string-in-java – Ciro Santilli OurBigBook.com Mar 02 '15 at 10:50
17

Guava looks like a good option:

Iterables.toString(myIterable)

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
Ben
  • 171
  • 1
  • 2
13

System.out.println(Collection c) already print any type of collection in readable format. Only if collection contains user defined objects , then you need to implement toString() in user defined class to display content.

Shekhar
  • 149
  • 1
  • 2
11

Implement toString() on the class.

I recommend the Apache Commons ToStringBuilder to make this easier. With it, you just have to write this sort of method:

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

In order to get this sort of output:

Person@7f54[name=Stephen,age=29]

There is also a reflective implementation.

Tim Kist
  • 1,164
  • 1
  • 14
  • 38
Chinnery
  • 10,179
  • 2
  • 23
  • 25
  • ToStringBuilder is usually more applicable for beans and objects that carry information, less so for complex data structures. If the stack object doesn't print all stored items, this won't help. – Uri Dec 27 '08 at 21:30
  • 2
    usage of reflection ToStringBuilder, HashCodeBuilder and EqualsBuilder is highly inefective. Though the output is ok, these classes are hardly the performance peak of the week... – Jan Hruby Nov 30 '12 at 08:34
  • 2
    The question explicitly says the class is a built-in collection, so toString() can't be modified. – Rasmus Kaj Oct 23 '13 at 09:30
8

I agree with the above comments about overriding toString() on your own classes (and about automating that process as much as possible).

For classes you didn't define, you could write a ToStringHelper class with an overloaded method for each library class you want to have handled to your own tastes:

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: Responding to the comment by xukxpvfzflbbld, here's a possible implementation for the cases mentioned previously.

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

}

This isn't a full-blown implementation, but just a starter.

joel.neely
  • 30,725
  • 9
  • 56
  • 64
7

You can use the "Objects" class from JAVA (which is available since 1.7)

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

Output: 1273, 123, 876, 897

Another possibility is to use the "MoreObjects" class from Google Guave, which provides many of useful helper functions:

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

Output: NameOfYourObject=[1273, 123, 876, 897]

Guava docs

Chisey88
  • 569
  • 6
  • 13
  • 1
    `Objects.toString()` just calls `toString()` on the collection. In your example, this works because presumably `toString()` on the array-backed collection happens to pretty-print nicely. – GuyPaddock Oct 09 '16 at 16:56
6

In Java8

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

or

//to print with commas
stack.forEach(
    (ele) -> {
        System.out.print(ele + ",");
    }
);
Yogi
  • 1,527
  • 15
  • 21
6

With Apache Commons 3, you want to call

StringUtils.join(myCollection, ",")
JRA_TLL
  • 1,186
  • 12
  • 23
4

most collections have a useful toString() in java these days (Java7/8). So there is no need to do stream operations to concatenate what you need, just override toString of your value class in the collection and you get what you need.

both AbstractMap and AbstractCollection implement toString() by calling toString per element.

below is a testclass to show behaviour.

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

Update Java 14 (Mar 2020)

Records are now a preview feature not requiring you to override toString() if your class only holds data. Records implement a data contract, giving public readonly access to it's fields and implementing default functions for your convience, like comparison, toString and hashcode.

so once could implement Foo as follows with the behavior:

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

public class ToString {
  static record Foo(int i) { }
  
  public static void main(String[] args) {
    Foo f = new Foo(10);
    System.out.println(f.toString());
    // prints: Foo[i=10]

    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: [Foo[i=10], Foo[i=12], Foo[i=13], Foo[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=Foo[i=10], 12=Foo[i=12], 13=Foo[i=13], 14=Foo[i=14]}
  }
}
Alexander Oh
  • 24,223
  • 14
  • 73
  • 76
0

Be careful when calling Sop on Collection, it can throw ConcurrentModification Exception. Because internally toString method of each Collection internally calls Iterator over the Collection.

Marko
  • 20,385
  • 13
  • 48
  • 64
0

You can try using

org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(yourCollection);
Alfabravo
  • 7,493
  • 6
  • 46
  • 82
user1016765
  • 2,935
  • 2
  • 32
  • 48
0

Just Modified the previous example to print even collection containing user defined objects.

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

}
Anne
  • 26,765
  • 9
  • 65
  • 71
Shekhar
  • 149
  • 1
  • 2
0

If this is your own collection class rather than a built in one, you need to override its toString method. Eclipse calls that function for any objects for which it does not have a hard-wired formatting.

Uri
  • 88,451
  • 51
  • 221
  • 321
0

There are two ways you could simplify your work. 1. import Gson library. 2. use Lombok.

Both of them help you create String from object instance. Gson will parse your object, lombok will override your class object toString method.

I put an example about Gson prettyPrint, I create helper class to print object and collection of objects. If you are using lombok, you could mark your class as @ToString and print your object directly.

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

}

Dongcai Huang
  • 29
  • 1
  • 9
0

JSON

An alternative Solution could be converting your collection in the JSON format and print the Json-String. The advantage is a well formatted and readable Object-String without a need of implementing the toString().

Example using Google's 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
  • 602
  • 9
  • 22
0

Newer JDK already has AbstractCollection.toString() implemented, and Stack extends AbstractCollection so you just have to call toString() on your collection:

    public abstract class AbstractCollection<E> implements Collection<E> {
    ...
    public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";
    
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }
cdalxndr
  • 1,435
  • 1
  • 15
  • 20
-1

Should work for any collection except Map, but it's easy to support, too. Modify code to pass these 3 chars as arguments if needed.

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();
}
Display Name
  • 8,022
  • 3
  • 31
  • 66