我试图打印出一个列表的所有元素,但它是打印对象的指针,而不是值。
这是我的打印代码…
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
有人能告诉我为什么它不打印元素的值吗?
我试图打印出一个列表的所有元素,但它是打印对象的指针,而不是值。
这是我的打印代码…
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
有人能告诉我为什么它不打印元素的值吗?
当前回答
考虑一个List<String> stringList,它可以使用Java 8结构以多种方式打印:
stringList.forEach(System.out::println); // 1) Iterable.forEach
stringList.stream().forEach(System.out::println); // 2) Stream.forEach (order maintained generally but doc does not guarantee)
stringList.stream().forEachOrdered(System.out::println); // 3) Stream.forEachOrdered (order maintained always)
stringList.parallelStream().forEach(System.out::println); // 4) Parallel version of Stream.forEach (order not maintained)
stringList.parallelStream().forEachOrdered(System.out::println); // 5) Parallel version ofStream.forEachOrdered (order maintained always)
这些方法之间有什么不同?
第一种方法(Iterable.forEach)- 通常使用集合的迭代器,它被设计为快速失败,这意味着如果底层集合在迭代期间被结构修改,它将抛出ConcurrentModificationException。正如在ArrayList的文档中提到的:
结构修改是添加或删除一个或 更多的元素,或者显式地调整支持数组的大小;只是设置 元素的值不是结构修改。
它的意思是数组列表。对于每个设置值都是允许的,没有任何问题。在并发收集的情况下,例如ConcurrentLinkedQueue,迭代器将是弱一致的,这意味着在forEach中传递的操作甚至可以在不抛出ConcurrentModificationExceptionexception的情况下进行结构更改。但是这里的修改可能在迭代中可见,也可能不可见。
第二种方法(Stream.forEach)- 顺序没有定义。虽然它可能不会出现在连续流中,但规范并不能保证它。此外,该行为还必须是不干涉性质的。如doc中所述:
此操作的行为明显是非确定性的。为 平行流管道,此操作不保证 尊重溪流的遭遇顺序,因为这样做会牺牲 并行的好处。
第三种方法(Stream.forEachOrdered)- 该操作将按照流的遇到顺序执行。因此,每当顺序问题时,请使用forEachOrdered。正如文件中提到的:
在相遇中为此流的每个元素执行一个操作 如果流具有定义的遇到顺序,则为流的顺序。
当迭代一个同步集合时,第一种方法将获得集合的锁一次,并在所有对action方法的调用中保持它,但在流的情况下,他们使用集合的spliterator,它不锁,依赖于已经建立的不干扰规则。如果在迭代过程中修改了支持流的集合,则会抛出ConcurrentModificationException异常或可能出现不一致的结果。
第四种方法(Parallel Stream.forEach)- 正如已经提到的,在并行流的情况下,不能保证尊重遇到的顺序。有可能在不同的线程中对不同的元素执行不同的操作,而forEachOrdered则永远不会出现这种情况。
第五种方法(Parallel Stream.forEachOrdered)- forEachOrdered将按照源指定的顺序处理元素,而不管流是顺序的还是并行的。所以在并行流中使用这个是没有意义的。
其他回答
这取决于List中存储的对象类型,以及它是否有toString()方法的实现。System.out.println(list)应该打印所有标准java对象类型(String, Long, Integer等)。在这种情况下,如果我们使用自定义对象类型,那么我们需要重写自定义对象的toString()方法。
例子:
class Employee {
private String name;
private long id;
@Override
public String toString() {
return "name: " + this.name() +
", id: " + this.id();
}
}
测试:
class TestPrintList {
public static void main(String[] args) {
Employee employee1 =new Employee("test1", 123);
Employee employee2 =new Employee("test2", 453);
List<Employee> employees = new ArrayList(2);
employee.add(employee1);
employee.add(employee2);
System.out.println(employees);
}
}
我写了一个转储函数,它基本上打印出对象的公共成员,如果它没有覆盖toString()。可以很容易地将其扩展为调用getter。 Javadoc:
将给定对象转储到系统。Out,使用以下规则: 如果对象是Iterable,则它的所有组件都将被转储。 如果Object或它的一个超类覆盖了toString(),则“toString”将被转储 否则,该方法将为对象的所有公共成员递归调用
/**
* Dumps an given Object to System.out, using the following rules:<br>
* <ul>
* <li> If the Object is {@link Iterable}, all of its components are dumped.</li>
* <li> If the Object or one of its superclasses overrides {@link #toString()}, the "toString" is dumped</li>
* <li> Else the method is called recursively for all public members of the Object </li>
* </ul>
* @param input
* @throws Exception
*/
public static void dump(Object input) throws Exception{
dump(input, 0);
}
private static void dump(Object input, int depth) throws Exception{
if(input==null){
System.out.print("null\n"+indent(depth));
return;
}
Class<? extends Object> clazz = input.getClass();
System.out.print(clazz.getSimpleName()+" ");
if(input instanceof Iterable<?>){
for(Object o: ((Iterable<?>)input)){
System.out.print("\n"+indent(depth+1));
dump(o, depth+1);
}
}else if(clazz.getMethod("toString").getDeclaringClass().equals(Object.class)){
Field[] fields = clazz.getFields();
if(fields.length == 0){
System.out.print(input+"\n"+indent(depth));
}
System.out.print("\n"+indent(depth+1));
for(Field field: fields){
Object o = field.get(input);
String s = "|- "+field.getName()+": ";
System.out.print(s);
dump(o, depth+1);
}
}else{
System.out.print(input+"\n"+indent(depth));
}
}
private static String indent(int depth) {
StringBuilder sb = new StringBuilder();
for(int i=0; i<depth; i++)
sb.append(" ");
return sb.toString();
}
从Java 8开始,List继承了一个默认的“forEach”方法,你可以将它与方法引用“System”结合起来使用。输出::println”像这样:
list.forEach(System.out::println);
使用String.join () 例如:
System.out.print(String.join("\n", list));
用于String数组的列表
list.forEach(s -> System.out.println(Arrays.toString((String[]) s )));