Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing Java Collections Nicely (toString Doesn't Return Pretty Output)

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?

like image 536
Elazar Leibovich Avatar asked Dec 27 '08 20:12

Elazar Leibovich


12 Answers

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

System.out.println(Arrays.toString(stack.toArray()));
like image 124
Zach Langley Avatar answered Nov 16 '22 00:11

Zach Langley


String.join(",", yourIterable);

(Java 8)

like image 44
user1016765 Avatar answered Nov 16 '22 00:11

user1016765


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.

like image 26
bsmk Avatar answered Nov 16 '22 01:11

bsmk


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

like image 26
tlavarea Avatar answered Nov 16 '22 00:11

tlavarea


Guava looks like a good option:

Iterables.toString(myIterable)

like image 37
Ben Avatar answered Nov 16 '22 01:11

Ben


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.

like image 34
Chinnery Avatar answered Nov 16 '22 00:11

Chinnery


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.

like image 23
joel.neely Avatar answered Nov 16 '22 01:11

joel.neely


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.

like image 27
Shekhar Avatar answered Nov 16 '22 00:11

Shekhar


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

like image 24
Chisey88 Avatar answered Nov 15 '22 23:11

Chisey88


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 + ",");
    }
);
like image 23
Yogi Avatar answered Nov 16 '22 01:11

Yogi


With Apache Commons 3, you want to call

StringUtils.join(myCollection, ",")
like image 43
JRA_TLL Avatar answered Nov 15 '22 23:11

JRA_TLL


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]}
  }
}
like image 35
Alexander Oh Avatar answered Nov 16 '22 01:11

Alexander Oh