我希望Stack<Integer>
像 Eclipse 调试器那样打印一个对象(即[1,2,3...]
),但打印它out = "output:" + stack
并不会返回这个好的结果。
澄清一下,我说的是 Java 的内置集合,所以我不能覆盖它的toString()
.
我怎样才能得到一个很好的可打印版本的堆栈?
我希望Stack<Integer>
像 Eclipse 调试器那样打印一个对象(即[1,2,3...]
),但打印它out = "output:" + stack
并不会返回这个好的结果。
澄清一下,我说的是 Java 的内置集合,所以我不能覆盖它的toString()
.
我怎样才能得到一个很好的可打印版本的堆栈?
您可以将其转换为数组,然后使用以下命令打印出来Arrays.toString(Object[])
:
System.out.println(Arrays.toString(stack.toArray()));
String.join(",", yourIterable);
(Java 8)
使用 java 8 流和收集器可以轻松完成:
String format(Collection<?> c) {
String s = c.stream().map(Object::toString).collect(Collectors.joining(","));
return String.format("[%s]", s);
}
首先我们使用map
withObject::toString
创建Collection<String>
,然后使用加入收集器将集合中的每个项目,
作为分隔符加入。
Apache Commons 项目提供的 MapUtils 类提供了MapUtils.debugPrint
一种可以漂亮地打印您的地图的方法。
番石榴看起来是个不错的选择:
System.out.println(Collection c) 已经以可读格式打印任何类型的集合。只有当集合包含用户定义的对象时,才需要在用户定义的类中实现 toString() 来显示内容。
在类上实现 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.
}
编辑:回应 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();
}
}
这不是一个完整的实现,而只是一个开始。
您可以使用JAVA 中的“对象”类(自 1.7 起可用)
Collection<String> myCollection = Arrays.asList("1273","123","876","897");
Objects.toString(myCollection);
输出:1273、123、876、897
另一种可能性是使用Google Guave 的“MoreObjects”类,它提供了许多有用的辅助函数:
MoreObjects.toStringHelper(this).add("NameOfYourObject", myCollection).toString());
输出:NameOfYourObject=[1273, 123, 876, 897]
在 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, ",")
如今,大多数集合在 Java 中都有用toString()
(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 }}
}
}
toString()
记录现在是一项预览功能,如果您的类只保存数据,则不需要您覆盖。Records 实现了一个数据契约,为它的字段提供公共只读访问权限,并为您的方便实现默认函数,如比较、toString 和哈希码。
所以一旦可以实现Foo
如下行为:
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]}
}
}
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);
}
如果这是你自己的集合类而不是内置的,你需要重写它的 toString 方法。Eclipse 为没有硬连线格式的任何对象调用该函数。
刚刚修改了前面的示例以打印包含用户定义对象的偶数集合。
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));
}
}
在 Collection 上调用 Sop 时要小心,它可能会抛出ConcurrentModification
异常。因为toString
每个集合的内部方法在内部调用Iterator
集合。
您可以尝试使用
org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(yourCollection);
有两种方法可以简化您的工作。1.导入Gson库。2.使用龙目岛。
它们都可以帮助您从对象实例创建字符串。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(","));
}
}
较新的 JDK 已经AbstractCollection.toString()
实现并Stack
扩展AbstractCollection
,因此您只需调用toString()
您的集合:
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(' ');
}
}
应该适用于除 之外的任何集合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();
}