Mencetak Koleksi Java dengan Baik (toString Tidak Mengembalikan Output Cukup)

211

Saya ingin mencetak Stack<Integer>objek sebaik debugger Eclipse (yaitu [1,2,3...]) tetapi mencetaknya dengan out = "output:" + stacktidak mengembalikan hasil yang bagus ini.

Hanya untuk memperjelas, saya berbicara tentang koleksi bawaan Java jadi saya tidak bisa menimpanya toString().

Bagaimana saya bisa mendapatkan versi tumpukan yang bisa dicetak?

Elazar Leibovich
sumber
7
Setidaknya pada Java 7, AbstractCollection@toString(dan dengan demikian String + Stack) sudah mencetaknya seperti yang Anda inginkan.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

317

Anda bisa mengonversinya menjadi sebuah array dan kemudian mencetaknya dengan Arrays.toString(Object[]):

System.out.println(Arrays.toString(stack.toArray()));
Zach Langley
sumber
11
Saya suka itu. Sederhana, bersih. Sejujurnya Koleksi membutuhkan metode toString juga, tetapi ini berfungsi juga.
Tovi7
1
@ Tovi7 Mungkin tidak karena kebanyakan Koleksi OOTB sudah menyediakan toString () s yang dapat dibaca, sedangkan array tidak.
Max Nanasy
@Boosha juga membutuhkan O (n) waktu untuk mengubah tumpukan menjadi string dan O (n) waktu untuk mencetak string ke konsol
Zach Langley
stack.toArray()mungkin sangat mahal, cpu, waktu dan memori. Solusi yang diulang atas koleksi asli / iterable mungkin akan lebih sedikit memakan sumber daya.
AlikElzin-kilaka
52
String.join(",", yourIterable);

(Java 8)

pengguna1016765
sumber
12
yourIterable harus Iterable <? meluas CharSequence>
Nathan
3
String.join (",", yourCollection.stream (). Map (o -> o.toString ()). Collect (Collectors.toList ()))
user1016765
@ user1016765 yourCollection.stream().map( o -> o.toString() ).collect( joining(",") ))lebih baik karena Anda membacanya dari kiri ke kanan, Anda tidak perlu melihat ke belakang untuk menghitung di otak Anda apa yang dilakukan dengan daftar perantara
cdalxndr
18

Dengan java 8 stream dan collector, hal itu dapat dilakukan dengan mudah:

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

pertama kita gunakan mapdengan Object::toStringuntuk membuat Collection<String>dan kemudian menggunakan bergabung dengan kolektor untuk bergabung setiap item dalam koleksi dengan ,sebagai pembatas.

bsmk
sumber
22
Saya harus menahan diri untuk tidak menghapus kata 'mudah' dari jawaban ;-) Collections.toString(stack)akan mudah.
FrVaBe
Mengapa panggilan ke String.format ()? Apakah hanya untuk mendapatkan tanda kurung?
Jolta
18

Kelas MapUtils yang ditawarkan oleh proyek Apache Commons menawarkan MapUtils.debugPrintmetode yang akan cukup mencetak peta Anda.

tlavarea
sumber
Tidak yang saya tahu. Saya tidak terlalu akrab dengan perpustakaan Guava tetapi saya tidak akan terkejut jika ada.
tlavarea
Tidak perlu untuk ini, setidaknya di Java 6, karena AbstractMap # toString sudah melakukannya. Hanya pertanyaan peta: stackoverflow.com/questions/2828252/map-to-string-in-java
Ciro Santilli 郝海东 冠状 病 六四 事件 事件 法轮功
12

System.out.println (Collection c) sudah mencetak semua jenis koleksi dalam format yang dapat dibaca. Hanya jika koleksi berisi objek yang ditentukan pengguna, maka Anda perlu menerapkan toString () di kelas yang ditentukan pengguna untuk menampilkan konten.

Shekhar
sumber
12

Menerapkan toString () di kelas.

Saya merekomendasikan Apache Commons ToStringBuilder untuk mempermudah ini. Dengan itu, Anda hanya perlu menulis metode semacam ini:

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

Untuk mendapatkan output seperti ini:

Orang @ 7f54 [nama = Stephen, umur = 29]

Ada juga implementasi yang reflektif .

Chinnery
sumber
ToStringBuilder biasanya lebih berlaku untuk kacang dan objek yang membawa informasi, kurang untuk struktur data yang kompleks. Jika objek tumpukan tidak mencetak semua item yang disimpan, ini tidak akan membantu.
Uri
2
penggunaan refleksi ToStringBuilder, HashCodeBuilder dan EqualsBuilder sangat tidak efektif. Meskipun hasilnya ok, kelas-kelas ini bukan puncak kinerja minggu ini ...
Jan Hruby
2
Pertanyaannya secara eksplisit mengatakan kelas adalah koleksi bawaan, jadi toString () tidak dapat dimodifikasi.
Rasmus Kaj
9

Saya setuju dengan komentar di atas tentang menimpa toString()kelas Anda sendiri (dan tentang mengotomatiskan proses itu sebanyak mungkin).

Untuk kelas yang tidak Anda definisikan, Anda bisa menulis ToStringHelperkelas dengan metode kelebihan beban untuk setiap kelas perpustakaan yang ingin Anda tangani sesuai selera Anda:

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: Menanggapi komentar oleh xukxpvfzflbbld, inilah kemungkinan implementasi untuk kasus yang disebutkan sebelumnya.

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

}

Ini bukan implementasi penuh, tetapi hanya pemula.

joel.neely
sumber
7

Anda dapat menggunakan kelas "Objek" dari JAVA (yang tersedia sejak 1.7)

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

Output: 1273, 123, 876, 897

Kemungkinan lain adalah menggunakan "MoreObjects" dari Google Guave , yang menyediakan banyak fungsi pembantu yang bermanfaat:

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

Output: NameOfYourObject = [1273, 123, 876, 897]

Jambu docs

Chisey88
sumber
1
Objects.toString()hanya memanggil toString()koleksi. Dalam contoh Anda, ini berfungsi karena mungkin toString()pada koleksi yang didukung array terjadi cukup baik cetak.
GuyPaddock
3

Dengan Apache Commons 3 , Anda ingin menelepon

StringUtils.join(myCollection, ",")
JRA_TLL
sumber
3

Di Java8

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

atau

//to print with commas
stack.forEach(
    (ele) -> {
        System.out.print(ele + ",");
    }
);
YÒGÎ
sumber
1

Hanya Memodifikasi contoh sebelumnya untuk mencetak koleksi genap yang berisi objek yang ditentukan pengguna.

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

}
Shekhar
sumber
1

sebagian besar koleksi memiliki manfaat toString()di java hari ini (Java7 / 8). Jadi tidak perlu melakukan operasi streaming untuk menggabungkan apa yang Anda butuhkan, cukup timpa toStringkelas nilai Anda dalam koleksi dan Anda mendapatkan apa yang Anda butuhkan.

baik AbstractMap dan AbstractCollection menerapkan toString () dengan menelepon toString per elemen.

di bawah ini adalah testclass untuk menunjukkan perilaku.

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 }}
  }
}
Alex
sumber
1

JSON

Solusi alternatif dapat mengubah koleksi Anda dalam format JSON dan mencetak Json-String. Keuntungannya adalah Object-String yang diformat dengan baik dan mudah dibaca tanpa perlu mengimplementasikan toString().

Contoh menggunakan 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);
}
tobsob
sumber
0

Jika ini adalah kelas koleksi Anda sendiri daripada yang dibangun dalam satu, Anda perlu mengganti metode toString-nya. Eclipse memanggil fungsi itu untuk objek apa pun yang tidak memiliki format kabel.

Uri
sumber
Dan bagaimana gerhana memformat kelas-kelas tersebut dengan format yang terprogram? Itu yang saya cari.
Elazar Leibovich
0

Hati-hati saat memanggil Sop di Koleksi, itu bisa membuang ConcurrentModificationPengecualian. Karena toStringmetode internal setiap Koleksi secara internal memanggil IteratorKoleksi.

Harneet
sumber
0

Seharusnya berfungsi untuk koleksi apa pun kecuali Map, tetapi juga mudah didukung. Ubah kode untuk meneruskan 3 karakter ini sebagai argumen jika diperlukan.

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();
}
Nama tampilan
sumber
0

Anda dapat mencoba menggunakan

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

Ada dua cara untuk menyederhanakan pekerjaan Anda. 1. impor perpustakaan Gson. 2. gunakan Lombok.

Keduanya membantu Anda membuat String dari objek instance. Gson akan mem-parsing objek Anda, lombok akan menimpa objek kelas Anda dengan metode String.

Saya memberi contoh tentang Gson prettyPrint, saya membuat kelas pembantu untuk mencetak objek dan koleksi objek. Jika Anda menggunakan lombok, Anda dapat menandai kelas Anda sebagai @ToString dan mencetak objek Anda secara langsung.

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

}

Dongcai Huang
sumber