จะพิมพ์องค์ประกอบทั้งหมดของ List ใน Java ได้อย่างไร


236

ฉันพยายามที่จะพิมพ์องค์ประกอบทั้งหมดของ a Listแต่มันกำลังพิมพ์ตัวชี้ของค่าObjectมากกว่า

นี่คือรหัสการพิมพ์ของฉัน ...

for(int i=0;i<list.size();i++){
    System.out.println(list.get(i));
} 

ใครช่วยได้โปรดช่วยฉันทำไมมันไม่ได้พิมพ์ค่าขององค์ประกอบ


3
คุณListเป็นคนแบบไหน? แสดงวิธีที่คุณประกาศและสร้างอินสแตนซ์
โกโตะ

คุณต้องเรียก toString และคุณจะได้รับคำอธิบายของ class หรือแทนที่เมธอด toString สำหรับประเภทที่รายการนั้นมี
L7ColWinters

นั่นคือสิ่งที่คุณกำลังบอกให้พิมพ์ - คุณต้องการ toString หรือสตริงอื่นที่สามารถอ่านได้
Dave Newton

ArrayList <class> list = new ArrayList <class> ();
user1335361

4
for (Object obj : list) {System.out.println(obj);}โปรดทราบว่ามีไวยากรณ์ขนาดกะทัดรัดมากขึ้นคุณสามารถใช้เพื่อบรรลุในสิ่งเดียวกัน
aroth

คำตอบ:


114

นี่คือตัวอย่างบางส่วนเกี่ยวกับการพิมพ์ส่วนประกอบรายการ:

public class ListExample {

    public static void main(String[] args) {
        List<Model> models = new ArrayList<>();

        // TODO: First create your model and add to models ArrayList, to prevent NullPointerException for trying this example

        // Print the name from the list....
        for(Model model : models) {
            System.out.println(model.getName());
        }

        // Or like this...
        for(int i = 0; i < models.size(); i++) {
            System.out.println(models.get(i).getName());
        }
    }
}

class Model {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

1
การแนะนำModelชั้นเรียนมีความสัมพันธ์กับคำถามอย่างไร
Karl Richter

4
มันเป็นเพียงข้อสันนิษฐานเนื่องจากฉันไม่รู้ว่า Object ชนิดใดในรายการ
Crazenezz

477

ต่อไปนี้มีขนาดกะทัดรัดและหลีกเลี่ยงการวนซ้ำในโค้ดตัวอย่างของคุณ (และให้เครื่องหมายจุลภาคที่ดี):

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

อย่างไรก็ตามตามที่คนอื่น ๆ ได้ชี้ให้เห็นหากคุณไม่ได้ใช้วิธี toString () ที่เหมาะสมสำหรับวัตถุภายในรายการคุณจะได้รับพอยน์เตอร์พอยน์เตอร์ (รหัสแฮชในความเป็นจริง) ที่คุณกำลังสังเกตอยู่ นี่เป็นเรื่องจริงไม่ว่าพวกเขาจะอยู่ในรายการหรือไม่


18
list.toString()สิ่งที่เกี่ยวกับเฉพาะ
Jaskey

22
เพียงแค่ใช้ 'list.toString ()' จะไม่พิมพ์องค์ประกอบแต่ละอย่างเว้นแต่เป็นการใช้งานแบบกำหนดเองของส่วนต่อประสานรายการซึ่งจะแทนที่พฤติกรรมปกติ (เพื่อพิมพ์ชื่อคลาสและรหัสแฮชมากหรือน้อย)
Holly Cummins

1
หากพวกเขาใช้คลาสที่กำหนดเองและไม่ได้แทนที่toStringโซลูชันของคุณจะพิมพ์ชื่อคลาสและรหัสแฮช
Jaskey

มันพิมพ์เป็น [value1, value2, value3] เราสามารถพิมพ์แบบไม่มี [] ได้หรือไม่?
สิ้นสุด

จริงๆแล้ว @Jaskey พูดถูก - คำตอบของพวกเขาดีกว่า Arraysวิธีการจะเป็นประโยชน์สำหรับอาร์เรย์ AbstractCollectionแต่ไม่จำเป็นในขณะนี้สำหรับคลาสย่อย
Holly Cummins

100

ตั้งแต่ Java 8 รายการจะสืบทอดเมธอด "forEach" ดีฟอลต์ซึ่งคุณสามารถรวมกับการอ้างอิงเมธอด "System.out :: println" ดังนี้:

list.forEach(System.out::println);

2
@ Katja Hahn เป็นไปได้หรือไม่ที่จะผนวกหรือต่อท้ายสตริงเพื่อprintlnส่งออก?
gumkins

2
@gumkins ใช่คุณสามารถ ตัวอย่าง: Arrays.stream (สตริงใหม่ [] {"John", "Sansa", "Cersei"}) map (s -> "Hi" + s + "!") forEach (System.out :: println) ;
Tiago Mussi

40
System.out.println(list);//toString() is easy and good enough for debugging.

toString()ของAbstractCollectionจะสะอาดและง่ายพอที่จะทำเช่นนั้น AbstractListเป็น subclass ของAbstractCollection, จึงไม่จำเป็นต้องไม่มีห่วงและไม่มี toArray () ที่จำเป็น

ส่งคืนการแทนค่าสตริงของการรวบรวมนี้ การเป็นตัวแทนสตริงประกอบด้วยรายการองค์ประกอบของคอลเลกชันในลำดับที่พวกเขาจะถูกส่งกลับโดยตัววนซ้ำของมันล้อมรอบด้วยวงเล็บเหลี่ยม ("[]") องค์ประกอบที่อยู่ติดกันจะถูกคั่นด้วยอักขระ "," (เครื่องหมายจุลภาคและเว้นวรรค) องค์ประกอบจะถูกแปลงเป็นสตริงโดย String.valueOf (Object)

หากคุณใช้วัตถุที่กำหนดเองใด ๆ ในรายการของคุณพูดว่า Student คุณจะต้องแทนที่toString()วิธีการของมัน(มันจะดีกว่าที่จะแทนที่วิธีนี้) เพื่อให้ได้ผลลัพธ์ที่มีความหมาย

ดูตัวอย่างด้านล่าง:

public class TestPrintElements {

    public static void main(String[] args) {

        //Element is String, Integer,or other primitive type
        List<String> sList = new ArrayList<String>();
        sList.add("string1");
        sList.add("string2");
        System.out.println(sList);

        //Element is custom type
        Student st1=new Student(15,"Tom");
        Student st2=new Student(16,"Kate");
        List<Student> stList=new ArrayList<Student>();
        stList.add(st1);
        stList.add(st2);
        System.out.println(stList);
   }
}


public  class Student{
    private int age;
    private String name;

    public Student(int age, String name){
        this.age=age;
        this.name=name;
    }

    @Override
    public String toString(){
        return "student "+name+", age:" +age;
    }
}

เอาท์พุท:

[string1, string2]
[student Tom age:15, student Kate age:16]

เพราะคำตอบนี้ไม่ถูกต้องทั้งหมด มันใช้ความหลากหลายโดยที่ไม่รู้ตัว นี่คือลำดับชั้นของมรดกที่แท้จริงสำหรับ:list List -> Collection -> Iterable -> Objectระดับที่จริงสืบทอดจาก AbstractCollection ArrayListคือ ดังนั้นในตัวอย่างนี้เมื่อtoString()จะเรียกมันว่าพบว่าการดำเนินงานที่กำหนดไว้ในArrayList AbstractCollectionจดบันทึกลำดับชั้นการสืบทอดสำหรับArrayList:ArrayList -> AbstractList -> AbstractCollection -> Collection -> Iterable -> Object
anon58192932

20

วิธี Java 8 Streams ...

list.stream().forEach(System.out::println);

คำตอบเดียวกับของ Katja Hahn
Karl Richter

ไม่มันไม่ใช่ กระแสการใช้ประโยชน์จากเหมือง ()
แบรดลีย์ D

@BradleyD สิ่งที่ได้รับคือการรับรู้โดยการเพิ่มเลเยอร์ของวิธีการอื่นเรียกว่า?
Leon

15

วัตถุในรายการจะต้องtoStringนำมาใช้เพื่อให้พวกเขาพิมพ์สิ่งที่มีความหมายต่อหน้าจอ

นี่คือการทดสอบอย่างรวดเร็วเพื่อดูความแตกต่าง:

public class Test {

    public class T1 {
        public Integer x;
    }

    public class T2 {
        public Integer x;

        @Override
        public String toString() {
            return x.toString();
        }
    }

    public void run() {
        T1 t1 = new T1();
        t1.x = 5;
        System.out.println(t1);

        T2 t2 = new T2();
        t2.x = 5;
        System.out.println(t2);

    }

    public static void main(String[] args) {        
        new Test().run();
    }
}

และเมื่อสิ่งนี้ดำเนินการผลลัพธ์ที่พิมพ์ไปยังหน้าจอคือ:

t1 = Test$T1@19821f
t2 = 5

เนื่องจาก T1 ไม่ได้แทนที่เมธอด toString อินสแตนซ์ของมัน t1 จึงพิมพ์ออกมาเป็นสิ่งที่ไม่มีประโยชน์มาก ในทางตรงกันข้าม T2 จะแทนที่ toString ดังนั้นเราจึงควบคุมสิ่งที่มันพิมพ์เมื่อมันถูกใช้ใน I / O และเราเห็นสิ่งที่ดีกว่าบนหน้าจอเล็กน้อย


11

พิจารณาสิ่ง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)

วิธีการเหล่านี้แตกต่างจากกันอย่างไร

First Approach ( Iterable.forEach) - ตัววนซ้ำของคอลเลกชันถูกใช้โดยทั่วไปและถูกออกแบบมาให้ล้มเหลวอย่างรวดเร็วซึ่งหมายความว่ามันจะโยนConcurrentModificationExceptionหากคอลเลกชันพื้นฐานถูกปรับเปลี่ยนโครงสร้างในระหว่างการทำซ้ำ ตามที่กล่าวไว้ในเอกสารสำหรับArrayList:

การดัดแปลงโครงสร้างเป็นการดำเนินการใด ๆ ที่เพิ่มหรือลบองค์ประกอบหนึ่งรายการขึ้นไปหรือปรับขนาดอาร์เรย์สำรองอย่างชัดเจน เพียงการกำหนดค่าขององค์ประกอบไม่ใช่การปรับเปลี่ยนโครงสร้าง

ดังนั้นมันหมายถึงการArrayList.forEachตั้งค่าที่อนุญาตโดยไม่มีปัญหาใด ๆ และในกรณีที่มีการรวบรวมพร้อมกันเช่นConcurrentLinkedQueueตัววนซ้ำนั้นจะมีความสอดคล้องกันอย่างอ่อนซึ่งหมายความว่าการกระทำที่ผ่านforEachนั้นได้รับอนุญาตให้ทำการเปลี่ยนแปลงโครงสร้างได้โดยไม่ต้องConcurrentModificationExceptionถูกยกเว้น แต่ที่นี่การแก้ไขอาจหรือไม่อาจมองเห็นได้ในการทำซ้ำนั้น

Second Approach ( Stream.forEach) - คำสั่งไม่ได้ถูกกำหนด แม้ว่ามันอาจจะไม่เกิดขึ้นสำหรับลำธารเรียงตามลำดับ แต่สเปคไม่ได้รับประกัน นอกจากนี้การกระทำจะต้องไม่รบกวนธรรมชาติ ตามที่ระบุไว้ในdoc :

พฤติกรรมของการดำเนินการนี้เป็นแบบไม่ระบุชื่ออย่างชัดเจน สำหรับท่อส่งกระแสคู่ขนานการดำเนินการนี้ไม่รับประกันว่าจะเคารพต่อคำสั่งซื้อของลำธารเนื่องจากการทำเช่นนั้นจะเสียสละประโยชน์ของการขนาน

Third Approach ( Stream.forEachOrdered) - การดำเนินการจะดำเนินการตามลำดับการเผชิญหน้าของสตรีม ดังนั้นเมื่อใดก็ตามที่ลำดับการใช้forEachOrderedมีความสำคัญ ตามที่ระบุไว้ในเอกสาร :

ดำเนินการกับแต่ละองค์ประกอบของสตรีมนี้ตามลำดับพบของสตรีมหากสตรีมมีลำดับการเผชิญหน้าที่กำหนดไว้

ในขณะที่การทำซ้ำมากกว่าการเก็บรวบรวมข้อมูลให้ตรงกันวิธีแรกจะใช้เวลาล็อคคอลเลกชันครั้งและจะถือมันในทุกสายไปยังวิธีการดำเนินการ แต่ในกรณีของลำธารที่พวกเขาใช้ spliterator คอลเลกชันที่ไม่ได้ล็อคและอาศัยอยู่กับกฎระเบียบที่จัดตั้งขึ้นแล้วไม่ใช่ -การรบกวน. ในกรณีที่คอลเลกชันสำรองกระแสถูกแก้ไขในระหว่างการทำซ้ำConcurrentModificationExceptionอาจจะโยนหรือผลลัพธ์ที่ไม่สอดคล้องกันอาจเกิดขึ้น

Fourth Approach (Parallel Stream.forEach) - ตามที่ได้กล่าวมาแล้วไม่มีการรับประกันว่าจะเคารพคำสั่งเผชิญหน้าตามที่คาดไว้ในกรณีของการสตรีมแบบขนาน เป็นไปได้ว่าการกระทำนั้นกระทำในเธรดที่แตกต่างกันสำหรับองค์ประกอบต่าง ๆ ซึ่งไม่สามารถเกิดforEachOrderedขึ้นได้

Fifth Approach (Parallel Stream.forEachOrdered) - The forEachOrderedจะประมวลผลองค์ประกอบตามลำดับที่ระบุโดยแหล่งที่มาโดยไม่คำนึงถึงความจริงที่ว่ากระแสเป็นลำดับหรือขนาน ดังนั้นจึงไม่มีเหตุผลที่จะใช้สิ่งนี้กับสตรีมแบบขนาน




7

ฉันต้องเผชิญกับปัญหาที่คล้ายกัน รหัสของฉัน:

List<Integer> leaveDatesList = new ArrayList<>();

.....inserted value in list.......

วิธีที่ 1: พิมพ์รายการใน for for loop

for(int i=0;i<leaveDatesList.size();i++){
    System.out.println(leaveDatesList.get(i));
}

วิธีที่ 2: การพิมพ์รายการใน forEach, for loop

for(Integer leave : leaveDatesList){
    System.out.println(leave);
}

วิธีที่ 3: พิมพ์รายการใน java 8

leaveDatesList.forEach(System.out::println);

5
  1. คุณยังไม่ได้ระบุประเภทของรายการที่มีหากเป็นชนิดข้อมูลดั้งเดิมคุณสามารถพิมพ์องค์ประกอบได้
  2. แต่ถ้าองค์ประกอบเป็นวัตถุดังนั้น Kshitij Mehta พูดถึงคุณต้องใช้ (แทนที่) วิธีการ "toString" ภายในวัตถุนั้น - หากยังไม่ได้ใช้งาน - และปล่อยให้มันส่งคืนบางสิ่งที่มีความหมายเต็มจากภายในวัตถุตัวอย่าง:

    class Person {
        private String firstName;
        private String lastName;
    
        @Override
        public String toString() {
            return this.firstName + " " + this.lastName;
        }
    }

3

System.out.println(list); ทำงานได้สำหรับฉัน

นี่คือตัวอย่างเต็มรูปแบบ:

import java.util.List;    
import java.util.ArrayList;

public class HelloWorld {
     public static void main(String[] args) {
        final List<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");
        System.out.println(list);
     }
}

[Hello, World]มันจะพิมพ์


ไม่แตกต่างจากที่อื่นคำตอบก่อนหน้านี้
Karl Richter

ฉันให้ตัวอย่างเต็มรูปแบบกับการนำเข้าคลาสและวิธีการหลักซึ่งคุณสามารถคัดลอกและวางและแสดงผลลัพธ์ ดังนั้นไม่มีเหตุผลที่จะลงคะแนนในความคิดของฉัน
jfmg


2

ฉันเขียนฟังก์ชั่นการถ่ายโอนข้อมูลซึ่งพิมพ์สมาชิกสาธารณะของวัตถุโดยพื้นฐานถ้ามันไม่ได้เกิน toString () หนึ่งสามารถขยายได้อย่างง่ายดายเพื่อเรียก getters javadoc:

ดัมพ์อ็อบเจ็กต์ที่กำหนดให้กับ System.out โดยใช้กฎต่อไปนี้:

  • หาก Object เป็น Iterable คอมโพเนนต์ทั้งหมดจะถูกดัมพ์
  • หากวัตถุหรือหนึ่งในซูเปอร์คลาสของมันแทนที่ 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();
}

2

สำหรับการวนซ้ำเพื่อพิมพ์เนื้อหาของรายการ:

List<String> myList = new ArrayList<String>();
myList.add("AA");
myList.add("BB");

for ( String elem : myList ) {
  System.out.println("Element : "+elem);
}

ผลลัพธ์ :

Element : AA
Element : BB

หากคุณต้องการพิมพ์ในบรรทัดเดียว (สำหรับข้อมูลเท่านั้น):

String strList = String.join(", ", myList);
System.out.println("Elements : "+strList);

ผลลัพธ์ :

Elements : AA, BB


1

ฉันกำลังจะทำงานในตอนนี้ ...

List<Integer> a = Arrays.asList(1, 2, 3);
List<Integer> b = Arrays.asList(3, 4);
List<int[]> pairs = a.stream()
  .flatMap(x -> b.stream().map(y -> new int[]{x, y}))
  .collect(Collectors.toList());

Consumer<int[]> pretty = xs -> System.out.printf("\n(%d,%d)", xs[0], xs[1]);
pairs.forEach(pretty);

1

มันขึ้นอยู่กับประเภทของวัตถุที่เก็บอยู่ในListและไม่ว่าจะมีการใช้งานสำหรับtoString()วิธีการ System.out.println(list)ควรพิมพ์ทุกประเภทที่วัตถุ java มาตรฐาน ( String, Long, Integerฯลฯ ) ในกรณีที่ถ้าเราใช้ประเภทวัตถุที่กำหนดเองแล้วเราต้องoverride 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);
   }
}

0
public static void main(String[] args) {
        answer(10,60);

    }
    public static void answer(int m,int k){
        AtomicInteger n = new AtomicInteger(m);
        Stream<Integer> stream = Stream.generate(() -> n.incrementAndGet()).limit(k);
        System.out.println(Arrays.toString(stream.toArray()));
    }

0

พยายามที่จะแทนที่ toString () วิธีการตามที่คุณต้องการว่าองค์ประกอบจะถูกพิมพ์ ดังนั้นวิธีการพิมพ์อาจเป็นดังนี้:

for(int i=0;i<list.size();i++){
    System.out.println(list.get(i).toString());
} 

นั่นคือสิ่งที่รหัสของ OP ทำ การเรียกเพื่อtoStringเป็นนัย
Karl Richter

-2
   List<String> textList=  messageList.stream()
                            .map(Message::getText)
                            .collect(Collectors.toList());

        textList.stream().forEach(System.out::println);
        public class Message  {

        String name;
        String text;

        public Message(String name, String text) {
            this.name = name;
            this.text = text;
        }

        public String getName() {
            return name;
        }

      public String getText() {
        return text;
     }
   }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.