In các bộ sưu tập Java một cách độc đáo (toString không trả lại kết quả đầu ra đẹp)


211

Tôi muốn in một Stack<Integer>đối tượng độc đáo như trình gỡ lỗi Eclipse thực hiện (nghĩa là [1,2,3...]) nhưng in nó out = "output:" + stackkhông mang lại kết quả tốt đẹp này.

Để làm rõ, tôi đang nói về bộ sưu tập dựng sẵn của Java vì vậy tôi không thể ghi đè lên nó toString().

Làm thế nào tôi có thể có được một phiên bản có thể in đẹp của ngăn xếp?


7
Ít nhất là từ Java 7, AbstractCollection@toString(và do đó String + Stack) đã in nó như bạn muốn.
Ciro Santilli 郝海东 冠状 病 事件 法轮功

Câu trả lời:


317

Bạn có thể chuyển đổi nó thành một mảng và sau đó in ra Arrays.toString(Object[]):

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

11
Tôi thích nó. Đơn giản, sạch sẽ. Thành thật mà nói Bộ sưu tập cũng cần một phương thức toString, nhưng điều này cũng hoạt động.
Tovi7

1
@ Tovi7 Có lẽ không phải vì hầu hết các Bộ sưu tập OOTB đã cung cấp các toString () có thể đọc được, trong khi các mảng thì không.
Max Nanasy

@Boosha cũng mất O (n) thời gian để chuyển đổi ngăn xếp thành chuỗi và thời gian O (n) để in chuỗi sang bàn điều khiển
Zach Langley

stack.toArray()có thể rất tốn kém, cpu, thời gian và bộ nhớ khôn ngoan. Một giải pháp lặp lại trên bộ sưu tập ban đầu / lặp có lẽ sẽ tiêu tốn ít tài nguyên hơn.
AlikElzin-kilaka

52
String.join(",", yourIterable);

(Java 8)


12
yourIterable phải được lặp lại <? kéo dài CharSequence>
Nathan

3
String.join (",", yourCollection.stream (). Map (o -> o.toString ()). Thu thập (Collector.toList ()))
user1016765

@ user1016765 yourCollection.stream().map( o -> o.toString() ).collect( joining(",") ))tốt hơn vì bạn đọc nó từ trái sang phải, bạn không cần nhìn lại phía trước để tính toán trong não những gì được thực hiện với danh sách trung gian
cdalxndr

18

Với java 8 stream và collector, nó có thể được thực hiện dễ dàng:

String format(Collection<?> c) {
  String s = c.stream().map(Object::toString).collect(Collectors.joining(","));
  return String.format("[%s]", s);
}

đầu tiên chúng ta sử dụng mapvới Object::toStringđể tạo Collection<String>và sau đó sử dụng tham gia collector để tham gia mọi mục trong bộ sưu tập với ,tư cách là dấu phân cách.


22
Tôi đã phải giữ lại để không loại bỏ từ 'dễ dàng' khỏi câu trả lời ;-) Collections.toString(stack)sẽ dễ dàng.
FrVaBe

Tại sao cuộc gọi đến String.format ()? Có phải chỉ để có được dấu ngoặc vuông?
Jolta

18

Lớp MapUtils được cung cấp bởi dự án Apache Commons cung cấp một MapUtils.debugPrintphương thức sẽ in đẹp bản đồ của bạn.


Không phải là tôi biết. Tôi không quen thuộc lắm với thư viện Guava nhưng tôi sẽ không ngạc nhiên nếu có.
tlavarea

Không cần điều này, ít nhất là trong Java 6, vì AbstractMap # toString đã làm điều đó rồi. Câu hỏi duy nhất trên bản đồ: stackoverflow.com/questions/2828252/map-to-opes-in-java
Ciro Santilli 冠状 病 六四 事件 法轮功

12

System.out.println (Bộ sưu tập c) đã in bất kỳ loại bộ sưu tập nào ở định dạng có thể đọc được. Chỉ khi bộ sưu tập chứa các đối tượng do người dùng xác định, thì bạn cần triển khai toString () trong lớp do người dùng xác định để hiển thị nội dung.


12

Thực hiện toString () trên lớp.

Tôi khuyên dùng Apache Commons ToStringBuilder để làm điều này dễ dàng hơn. Với nó, bạn chỉ cần viết loại phương thức này:

public String toString() {
     return new ToStringBuilder(this).
       append("name", name).
       append("age", age).
       toString(); 
}

Để có được loại đầu ra này:

Người @ 7f54 [tên = Stephen, tuổi = 29]

Ngoài ra còn có một thực hiện phản ánh .


ToStringBuilder thường được áp dụng nhiều hơn cho các bean và các đối tượng mang thông tin, ít hơn cho các cấu trúc dữ liệu phức tạp. Nếu đối tượng ngăn xếp không in tất cả các mục được lưu trữ, điều này sẽ không giúp ích.
Uri

2
việc sử dụng sự phản chiếu ToStringBuilder, HashCodeBuilder và EqualsBuilder rất kém hiệu quả. Mặc dù đầu ra vẫn ổn, nhưng các lớp này hầu như không phải là đỉnh cao hiệu suất trong tuần ...
Jan Hruby

2
Câu hỏi nói rõ ràng rằng lớp là một bộ sưu tập tích hợp, do đó toString () không thể được sửa đổi.
Rasmus Kaj


9

Tôi đồng ý với các ý kiến ​​trên về việc ghi đè toString()lên các lớp của riêng bạn (và về việc tự động hóa quá trình đó càng nhiều càng tốt).

Đối với các lớp bạn không xác định, bạn có thể viết một ToStringHelperlớp với phương thức quá tải cho mỗi lớp thư viện mà bạn muốn xử lý theo sở thích của riêng bạn:

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: Trả lời bình luận của xukxpvfzflbbld, đây là một triển khai có thể cho các trường hợp được đề cập trước đây.

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

}

Đây không phải là một triển khai đầy đủ, mà chỉ là một khởi đầu.


7

Bạn có thể sử dụng lớp "Đối tượng" từ JAVA (có sẵn từ 1.7)

Collection<String> myCollection = Arrays.asList("1273","123","876","897");
Objects.toString(myCollection);

Đầu ra: 1273, 123, 876, 897

Một khả năng khác là sử dụng lớp "MoreObjects" từ Google Guave , cung cấp nhiều hàm trợ giúp hữu ích:

MoreObjects.toStringHelper(this).add("NameOfYourObject", myCollection).toString());

Đầu ra: NameOfYourObject = [1273, 123, 876, 897]

Tài liệu ổi


1
Objects.toString()chỉ cần gọi toString()vào bộ sưu tập. Trong ví dụ của bạn, điều này hoạt động vì có lẽ toString()trên bộ sưu tập được hỗ trợ mảng xảy ra với bản in đẹp.
GuyPaddock

3

Với Apache Commons 3 , bạn muốn gọi

StringUtils.join(myCollection, ",")

3

Trong Java8

//will prints each element line by line
stack.forEach(System.out::println);

hoặc là

//to print with commas
stack.forEach(
    (ele) -> {
        System.out.print(ele + ",");
    }
);

1

Chỉ cần sửa đổi ví dụ trước để in ngay cả bộ sưu tập có chứa các đối tượng do người dùng xác định.

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

}

1

hầu hết các bộ sưu tập có ích toString()trong java ngày nay (Java7 / 8). Vì vậy, không cần thực hiện các thao tác truyền phát để ghép nối những gì bạn cần, chỉ cần ghi đè toStringlớp giá trị của bạn trong bộ sưu tập và bạn có được những gì bạn cần.

cả AbstractMapAbstractCollection đều thực hiện toString () bằng cách gọi toString cho mỗi phần tử.

dưới đây là một lớp kiểm tra để hiển thị hành vi.

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

1

JSON

Một giải pháp thay thế có thể là chuyển đổi bộ sưu tập của bạn ở định dạng JSON và in Json-String. Ưu điểm là một Chuỗi đối tượng được định dạng và dễ đọc mà không cần triển khai toString().

Ví dụ sử dụng Gson của Google :

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

0

Nếu đây là lớp bộ sưu tập của riêng bạn chứ không phải là một lớp tích hợp, bạn cần ghi đè phương thức toString của nó. Eclipse gọi hàm đó cho bất kỳ đối tượng nào mà nó không có định dạng cứng.


Và làm thế nào để định dạng nhật thực các lớp w / định dạng cứng? Đó là những gì tôi đang tìm kiếm.
Elazar Leibovich

0

Hãy cẩn thận khi gọi Sop trên Bộ sưu tập, nó có thể ném ConcurrentModificationNgoại lệ. Bởi vì toStringphương thức bên trong của mỗi Bộ sưu tập gọi nội bộ Iteratorqua Bộ sưu tập.


0

Nên hoạt động cho bất kỳ bộ sưu tập nào ngoại trừ Map, nhưng nó cũng dễ hỗ trợ. Sửa đổi mã để vượt qua 3 ký tự này làm đối số nếu cần.

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

0

Bạn có thể thử sử dụng

org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString(yourCollection);

0

Có hai cách bạn có thể đơn giản hóa công việc của mình. 1. nhập thư viện Gson. 2. sử dụng Lombok.

Cả hai đều giúp bạn tạo String từ đối tượng. Gson sẽ phân tích đối tượng của bạn, lombok sẽ ghi đè lên đối tượng lớp của bạn phương thức toString.

Tôi lấy một ví dụ về Gson beautifulPrint, tôi tạo lớp trình trợ giúp để in đối tượng và bộ sưu tập các đối tượng. Nếu bạn đang sử dụng lombok, bạn có thể đánh dấu lớp của mình là @ToString và in đối tượng của bạn trực tiếp.

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

}

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.