Làm cách nào để in ra tất cả các thành phần của Danh sách trong Java?


236

Tôi đang cố gắng in ra tất cả các yếu tố của a List, tuy nhiên nó đang in con trỏ của Objectgiá trị chứ không phải giá trị.

Đây là mã in của tôi ...

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

Ai đó có thể vui lòng giúp tôi tại sao nó không in giá trị của các yếu tố.


3
Những loại bạn đã tuyên bố Listlà? Chỉ cho chúng tôi cách bạn khai báo và khởi tạo nó.
Makoto

bạn phải gọi toString và bạn sẽ nhận được lời giải thích về lớp hoặc ghi đè phương thức toString cho loại mà danh sách chứa
L7ColWinters

Đó là những gì bạn đang bảo nó in - bạn cần một chuỗi toString khác hoặc chuỗi có thể đọc khác.
Dave Newton

ArrayList <class> list = new ArrayList <class> ();
dùng1335361

4
Lưu ý rằng có một cú pháp nhỏ gọn hơn mà bạn có thể sử dụng để thực hiện điều tương tự : for (Object obj : list) {System.out.println(obj);}.
aroth

Câu trả lời:


114

Dưới đây là một số ví dụ về việc in ra thành phần danh sách:

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
Làm thế nào là giới thiệu của Modellớp liên quan đến câu hỏi?
Karl Richter

4
Đó chỉ là một giả định, vì tôi không biết loại Đối tượng nào trong danh sách.
Crazenezz

475

Dưới đây là nhỏ gọn và tránh vòng lặp trong mã ví dụ của bạn (và cung cấp cho bạn dấu phẩy đẹp):

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

Tuy nhiên, như những người khác đã chỉ ra, nếu bạn không có các phương thức toString () hợp lý được triển khai cho các đối tượng trong danh sách, bạn sẽ nhận được các con trỏ đối tượng (thực tế là mã băm) mà bạn đang quan sát. Điều này đúng cho dù họ có trong danh sách hay không.


18
Còn gì list.toString()nữa.
Jaskey

22
Chỉ sử dụng 'list.toString ()' sẽ không in các phần tử riêng lẻ, trừ khi đó là triển khai tùy chỉnh giao diện Danh sách ghi đè hành vi thông thường (để in tên lớp và mã băm, ít nhiều).
Holly Cummins

1
Nếu họ sử dụng lớp tùy chỉnh và không ghi đè toString, giải pháp của bạn cũng sẽ in tên lớp và mã băm của nó.
Jaskey

Nó in dưới dạng [value1, value2, value3]. Chúng tôi có thể in như không có [] không?
cụt

Trên thực tế, @Jaskey đã đúng - câu trả lời của họ là tốt hơn. Các Arraysphương pháp rất hữu ích cho các mảng, nhưng không phải bây giờ cần thiết cho lớp con của AbstractCollection.
Holly Cummins

100

Kể từ Java 8, List thừa hưởng một phương thức "forEach" mặc định mà bạn có thể kết hợp với tham chiếu phương thức "System.out :: println" như thế này:

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

2
@Katja Hahn, có thể nối thêm hoặc thêm một số chuỗi vào printlnđầu ra không?
kẹo cao su

2
@gumkins, CÓ, bạn có thể. Ví dụ: Arrays.stream (Chuỗi mới [] {"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()của AbstractCollection sẽ có đủ sạch và dễ dàng để làm điều đó . AbstractListlà một lớp con của AbstractCollection, vì vậy không cần vòng lặp và không cần toArray ().

Trả về một chuỗi đại diện của bộ sưu tập này. Biểu diễn chuỗi bao gồm một danh sách các phần tử của bộ sưu tập theo thứ tự chúng được trả về bởi trình lặp của nó, được đặt trong dấu ngoặc vuông ("[]"). Các phần tử liền kề được phân tách bằng các ký tự "," (dấu phẩy và dấu cách). Các phần tử được chuyển đổi thành chuỗi như String.valueOf (Object).

Nếu bạn đang sử dụng bất kỳ đối tượng tùy chỉnh nào trong danh sách của mình, giả sử Sinh viên, bạn cần ghi đè toString()phương thức của nó (luôn luôn tốt khi ghi đè phương thức này) để có đầu ra có ý nghĩa

Xem ví dụ dưới đây:

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

đầu ra:

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

Bởi vì câu trả lời này không hoàn toàn chính xác. Đó là sử dụng đa hình mà không nhận ra nó. Đây là hệ thống phân cấp thừa kế thực tế cho list: List -> Collection -> Iterable -> Object. Lớp thực sự kế thừa từ AbstractCollection là ArrayList. Vì vậy, trong ví dụ này khi toString()được gọi, nó tìm thấy việc ArrayListthực hiện được định nghĩa trong AbstractCollection. Lưu ý hệ thống phân cấp thừa kế cho ArrayList:ArrayList -> AbstractList -> AbstractCollection -> Collection -> Iterable -> Object
anon58192932

21

Cách tiếp cận Luồng Java 8 ...

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

câu trả lời tương tự như của Katja Hahn
Karl Richter

Không, không. Mỏ đòn bẩy của tôi ().
Bradley D

@BradleyD những lợi ích nào được nhận ra bằng cách thêm một lớp gọi phương thức khác vào đó?
Leon

15

Các đối tượng trong danh sách phải toStringthực hiện để chúng in một cái gì đó có ý nghĩa lên màn hình.

Đây là một thử nghiệm nhanh để thấy sự khác biệt:

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

Và khi điều này thực thi, kết quả được in ra màn hình là:

t1 = Test$T1@19821f
t2 = 5

Vì T1 không ghi đè phương thức toString, nên t1 của nó in ra như một thứ không hữu ích. Mặt khác, T2 ghi đè lênString, vì vậy chúng tôi kiểm soát những gì nó in khi được sử dụng trong I / O và chúng tôi thấy một cái gì đó tốt hơn một chút trên màn hình.


11

Hãy xem xét một List<String> stringListcái có thể được in theo nhiều cách bằng cách sử dụng các cấu trúc 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)

Những cách tiếp cận này khác nhau như thế nào?

Cách tiếp cận đầu tiên ( Iterable.forEach) - Trình lặp của bộ sưu tập thường được sử dụng và được thiết kế để không nhanh , điều đó có nghĩa là nó sẽ ném ConcurrentModificationExceptionnếu bộ sưu tập cơ bản được sửa đổi cấu trúc trong quá trình lặp. Như đã đề cập trong tài liệu cho ArrayList:

Một sửa đổi cấu trúc là bất kỳ hoạt động nào thêm hoặc xóa một hoặc nhiều phần tử hoặc thay đổi kích thước mảng sao lưu một cách rõ ràng; chỉ đơn thuần là thiết lập giá trị của một phần tử không phải là một sửa đổi cấu trúc.

Vì vậy, nó có nghĩa là để ArrayList.forEachthiết lập giá trị được cho phép mà không có bất kỳ vấn đề. Và trong trường hợp thu thập đồng thời, ví dụ ConcurrentLinkedQueue, trình lặp sẽ không nhất quán yếu, điều đó có nghĩa là các hành động được truyền vào forEachđược phép thực hiện ngay cả các thay đổi về cấu trúc mà không có ConcurrentModificationExceptionngoại lệ bị ném. Nhưng ở đây các sửa đổi có thể hoặc không thể nhìn thấy trong lần lặp đó.

Cách tiếp cận thứ hai ( Stream.forEach) - Thứ tự không xác định. Mặc dù nó có thể không xảy ra cho các luồng liên tiếp nhưng đặc tả không đảm bảo nó. Ngoài ra, hành động được yêu cầu là không can thiệp vào tự nhiên. Như đã đề cập trong doc :

Hành vi của hoạt động này là không rõ ràng. Đối với các đường ống dòng song song, hoạt động này không đảm bảo tôn trọng thứ tự gặp gỡ của luồng, vì làm như vậy sẽ hy sinh lợi ích của song song.

Cách tiếp cận thứ ba ( Stream.forEachOrdered) - Hành động sẽ được thực hiện theo thứ tự bắt gặp của luồng. Vì vậy, bất cứ khi nào vấn đề đặt hàng sử dụng forEachOrderedmà không có một ý nghĩ thứ hai. Như đã đề cập trong tài liệu :

Thực hiện một hành động cho từng thành phần của luồng này, theo thứ tự bắt gặp của luồng nếu luồng có thứ tự bắt gặp được xác định.

Trong khi lặp lại một bộ sưu tập được đồng bộ hóa , cách tiếp cận đầu tiên sẽ lấy khóa của bộ sưu tập một lần và sẽ giữ nó trên tất cả các phương thức gọi hành động, nhưng trong trường hợp các luồng chúng sử dụng bộ chia của bộ sưu tập, không khóa và dựa vào các quy tắc đã được thiết lập giao thoa. Trong trường hợp bộ sưu tập sao lưu luồng được sửa đổi trong quá trình lặp, một ConcurrentModificationExceptionkết quả sẽ bị ném hoặc không nhất quán có thể xảy ra.

Cách tiếp cận thứ tư (Song song Stream.forEach) - Như đã đề cập, không có gì đảm bảo tôn trọng thứ tự gặp gỡ như mong đợi trong trường hợp các luồng song song. Có thể hành động được thực hiện trong các luồng khác nhau cho các yếu tố khác nhau mà không bao giờ có thể xảy ra forEachOrdered.

Cách tiếp cận thứ năm (Song song Stream.forEachOrdered) - Ý forEachOrderedchí sẽ xử lý các phần tử theo thứ tự được chỉ định bởi nguồn bất kể thực tế là luồng là tuần tự hay song song. Vì vậy, nó không có ý nghĩa để sử dụng điều này với các luồng song song.




7

Tôi đã phải đối mặt với những vấn đề tương tự. Mã của tôi:

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

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

Cách 1: in danh sách trong vòng lặp for

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

Cách 2: in danh sách trong vòng lặp forEach, for

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

Cách 3: in danh sách trong java 8

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

5
  1. Bạn chưa chỉ định loại phần tử nào trong danh sách, nếu đó là kiểu dữ liệu nguyên thủy thì bạn có thể in ra các phần tử.
  2. Nhưng nếu các phần tử là các đối tượng thì như Kshitij Mehta đã đề cập, bạn cần triển khai (ghi đè) phương thức "toString" trong đối tượng đó - nếu nó chưa được triển khai - và để nó trả về một ý nghĩa đầy đủ từ bên trong đối tượng, ví dụ:

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

3

System.out.println(list); làm việc cho tôi

Dưới đây là một ví dụ đầy đủ:

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

Nó sẽ in [Hello, World].


Không khác với những câu trả lời trước đó
Karl Richter

Tôi đã đưa ra một ví dụ đầy đủ với nhập khẩu, lớp và phương thức chính mà bạn có thể sao chép và dán và hiển thị kết quả. Do đó, không có lý do gì để bỏ phiếu theo ý kiến ​​của tôi
jfmg

3

Để biết danh sách mảng String

list.forEach(s -> System.out.println(Arrays.toString((String[]) s )));

2

Tôi đã viết một hàm dump, trong đó cơ bản in ra các thành viên công khai của một đối tượng nếu nó không ghi đè lên toString (). Người ta có thể dễ dàng mở rộng nó để gọi getters. Javadoc:

Kết xuất một đối tượng đã cho vào System.out, sử dụng các quy tắc sau:

  • Nếu Object là Iterable, tất cả các thành phần của nó sẽ bị hủy.
  • Nếu đối tượng hoặc một trong các siêu lớp của nó ghi đè lênString (), "toString" sẽ bị hủy
  • Khác phương thức được gọi đệ quy cho tất cả các thành viên công khai của Đối tượng

/**
 * 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

Đối với vòng lặp để in nội dung của danh sách:

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

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

Kết quả :

Element : AA
Element : BB

Nếu bạn muốn in trong một dòng duy nhất (chỉ để biết thông tin):

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

Kết quả :

Elements : AA, BB

1
    list.stream().map(x -> x.getName()).forEach(System.out::println);

Loại xnào và nó liên quan đến câu hỏi của OP như thế nào?
Karl Richter

1

Tôi tình cờ làm việc này bây giờ ...

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

Nó phụ thuộc vào loại đối tượng được lưu trữ trong Listvà liệu nó có triển khai cho toString()phương thức hay không. System.out.println(list)nên in tất cả các loại đối tượng java tiêu chuẩn ( String, Long, Integervv). Trong trường hợp, nếu chúng ta đang sử dụng các loại đối tượng tùy chỉnh, thì chúng ta cần phảioverride toString() phương thức của đối tượng tùy chỉnh.

Thí dụ:

class Employee {
 private String name;
 private long id;

 @Override
 public String toString() {
   return "name: " + this.name() + 
           ", id: " + this.id();
 }  
}

Kiểm tra:

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

cố gắng ghi đè phương thức toString () như bạn muốn rằng phần tử sẽ được in. Vì vậy, phương pháp để in có thể là thế này:

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

Đó là những gì mã của OP làm. Cuộc gọi đến toStringlà ngầm.
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;
     }
   }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.