Cukup cetak Peta di Jawa


137

Saya mencari cara yang bagus untuk mencetak cantik a Map.

map.toString() beri saya: {key1=value1, key2=value2, key3=value3}

Saya ingin lebih banyak kebebasan dalam nilai entri peta saya dan saya mencari sesuatu yang lebih seperti ini: key1="value1", key2="value2", key3="value3"

Saya menulis kode kecil ini:

StringBuilder sb = new StringBuilder();
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Entry<String, String> entry = iter.next();
    sb.append(entry.getKey());
    sb.append('=').append('"');
    sb.append(entry.getValue());
    sb.append('"');
    if (iter.hasNext()) {
        sb.append(',').append(' ');
    }
}
return sb.toString();

Tapi saya yakin ada cara yang lebih elegan dan ringkas untuk melakukan ini.


1
kemungkinan duplikat Map to String di Java karena format yang diminta di sini dan format System.out.printlnyang terlalu mirip. Dan jika Anda menginginkan sesuatu yang unik, intinya adalah "cara mengulang peta di Jawa" yang tentunya memiliki banyak jawaban lain.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:


63

Atau masukkan logika Anda ke dalam kelas kecil yang rapi.

public class PrettyPrintingMap<K, V> {
    private Map<K, V> map;

    public PrettyPrintingMap(Map<K, V> map) {
        this.map = map;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        Iterator<Entry<K, V>> iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<K, V> entry = iter.next();
            sb.append(entry.getKey());
            sb.append('=').append('"');
            sb.append(entry.getValue());
            sb.append('"');
            if (iter.hasNext()) {
                sb.append(',').append(' ');
            }
        }
        return sb.toString();

    }
}

Pemakaian:

Map<String, String> myMap = new HashMap<String, String>();

System.out.println(new PrettyPrintingMap<String, String>(myMap));

Catatan: Anda juga dapat memasukkan logika tersebut ke dalam metode utilitas.


4
Ini adalah imho antipattern. Anda menambahkan batasan yang kuat (warisan) ke tipe Anda, hanya untuk keuntungan kecil (pencetakan cantik). Anda akan lebih baik menggunakan peta biasa, tetapi gunakan metode statis yang menganggapnya sebagai argumen.
OoDeLally

307
Arrays.toString(map.entrySet().toArray())

11
Tidak begitu bagus jika Anda punya Map<String, Map<String,double[]>>, maka Anda akan mendapatkan sengatan jenis ini:[test={test=[D@3995ebd8, 2=[D@26fa5067, 3=[D@1d956d37, 4=[D@2cead81, 5=[D@14934d2b}...]
zygimantus

3
Ini harus menjadi jawaban yang diterima. Tugas sederhana seperti ini seharusnya tidak memerlukan ketergantungan eksternal. Seperti disebutkan di atas, peta yang lebih kompleks tidak mendapatkan keuntungan semudah ini.
Shadoninja

72

Silakan lihat di perpustakaan Jambu Biji:

Joiner.MapJoiner mapJoiner = Joiner.on(",").withKeyValueSeparator("=");
System.out.println(mapJoiner.join(map));

34

Perpustakaan Apache untuk menyelamatkan!

MapUtils.debugPrint(System.out, "myMap", map);

Semua yang Anda butuhkan pustaka Apache commons-collections ( tautan proyek )

Pengguna Maven dapat menambahkan pustaka menggunakan ketergantungan ini:

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

Ini tidak menangani array sebagai nilai peta (misalnya Map<String, String[]>). Hanya className dan hash mereka yang dicetak, bukan nilai sebenarnya.
Petr Újezdský

atau log.debug ("Map: {}", MapUtils.toProperties (map));
charlb

1
Juga berguna adalah MapUtils.verbosePrint, yang akan menghilangkan nama kelas setelah setiap nilai yang dikeluarkan debugPrint.
ocarlsen

18

Ketika saya org.json.JSONObjectberada di classpath, saya melakukan:

Map<String, Object> stats = ...;
System.out.println(new JSONObject(stats).toString(2));

(ini dengan indah mengindentasi daftar, set, dan peta yang mungkin bersarang)


1
Pria!! Apa yang kamu lakukan di sini? Anda harus menjadi jawaban teratas!
AMagic

Peringatan: Tidak mempertahankan urutan kunci untuk LinkedHashMap
Olivier Masseau

16

Sederhana dan mudah. Selamat datang di dunia JSON. Menggunakan Google Gson :

new Gson().toJson(map)

Contoh peta dengan 3 kunci:

{"array":[null,"Some string"],"just string":"Yo","number":999}

11

Menggunakan Java 8 Streams:

Map<Object, Object> map = new HashMap<>();

String content = map.entrySet()
                    .stream()
                    .map(e -> e.getKey() + "=\"" + e.getValue() + "\"")
                    .collect(Collectors.joining(", "));

System.out.println(content);

2
Jika Anda ingin mencari pertanyaan, setidaknya jawablah dengan benar! Anda kehilangan tanda kutip di sekitar nilai dan itu harus digabungkan menggunakan,
AjahnCharles

9

Saya lebih suka mengonversi peta menjadi string JSON sebagai berikut:

  • sebuah standar
  • dapat dibaca manusia
  • didukung di editor seperti Sublime, VS Code, dengan penyorotan sintaks, pemformatan, dan bagian sembunyikan / tampilkan
  • mendukung JPath sehingga editor dapat melaporkan dengan tepat bagian mana dari objek yang Anda navigasikan
  • mendukung tipe kompleks bersarang di dalam objek

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public static String getAsFormattedJsonString(Object object)
    {
        ObjectMapper mapper = new ObjectMapper();
        try
        {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        }
        catch (JsonProcessingException e)
        {
            e.printStackTrace();
        }
        return "";
    }
    

4

Lihat kode untuk HashMap#toString()dan AbstractMap#toString()di sumber OpenJDK:

class java.util.HashMap.Entry<K,V> implements Map.Entry<K,V> {
       public final String toString() {
           return getKey() + "=" + getValue();
       }
   }
 class java.util.AbstractMap<K,V> {
     public String toString() {
         Iterator<Entry<K,V>> i = entrySet().iterator();
         if (! i.hasNext())
            return "{}";

        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key);
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(", ");
        }
    }
}

Jadi jika orang-orang dari OpenJDK tidak menemukan cara yang lebih elegan untuk melakukan ini, tidak ada :-)


3

Anda harus dapat melakukan apa yang Anda inginkan dengan melakukan:

System.out.println(map) sebagai contoh

Selama SEMUA objek Anda di peta telah memperluas toStringmetode yang akan Anda lihat:
{key1=value1, key2=value2}dengan cara yang bermakna

Jika ini untuk kode Anda, maka overiding toStringadalah kebiasaan yang baik dan saya sarankan Anda melakukannya sebagai gantinya.

Untuk contoh Anda di mana objek Anda berada String, Anda seharusnya baik-baik saja tanpa hal lain.
Yaitu System.out.println(map)akan mencetak apa yang Anda butuhkan tanpa kode tambahan


1
kunci dan nilainya adalah string; Saya pikir dia mendapatkan metode toString tertutup tbh.
Tom

Anda benar, tapi mungkin dia menyalin contoh sepele untuk menjelaskan maksudnya Tapi saya memperbarui jawaban
Cratylus

Ya, saya seharusnya menunjukkan bahwa peta saya adalah Map <String, String>. Tetapi saya juga menunjukkan bahwa saya menginginkan lebih banyak kebebasan dalam nilai entri saya, misalnya memiliki daftar yang dipisahkan koma dalam nilai entri. Jadi Map.toString () tidak akan berhasil.
space_monkey

Antarmuka java.util.Maptidak memiliki kontrak terkait toString(), jadi terserah pada Mapimplementasi sebenarnya apa yang akan terjadi System.out.println(map)-> PrintStream.println(map)-> String.valueOf(map)-> map.toString(). Kebetulan yang sering digunakan java.util.AbstractMapmenyediakan representasi string yang bagus untuk toString(). ... MapPenerapan lain mungkin jatuh kembali ke Object.toString(), yang menghasilkan tidak terlalu informatif com.example.MyMap@4e8c0de.
Abdull

2
public void printMapV2 (Map <?, ?> map) {
    StringBuilder sb = new StringBuilder(128);
    sb.append("{");
    for (Map.Entry<?,?> entry : map.entrySet()) {
        if (sb.length()>1) {
            sb.append(", ");
        }
        sb.append(entry.getKey()).append("=").append(entry.getValue());
    }
    sb.append("}");
    System.out.println(sb);
}

1

String result = objectMapper.writeValueAsString(map) - sesederhana ini!

Hasil:

{"2019-07-04T03:00":1,"2019-07-04T04:00":1,"2019-07-04T01:00":1,"2019-07-04T02:00":1,"2019-07-04T13:00":1,"2019-07-04T06:00":1 ...}

PS menambahkan Jackson JSON ke jalur kelas Anda.


0

Saya kira sesuatu seperti ini akan lebih bersih, dan memberi Anda lebih banyak fleksibilitas dengan format output (cukup ubah template):

    String template = "%s=\"%s\",";
    StringBuilder sb = new StringBuilder();
    for (Entry e : map.entrySet()) {
        sb.append(String.format(template, e.getKey(), e.getValue()));
    }
    if (sb.length() > 0) {
        sb.deleteCharAt(sb.length() - 1); // Ugly way to remove the last comma
    }
    return sb.toString();

Saya tahu harus menghapus koma terakhir itu jelek, tapi saya pikir itu lebih bersih daripada alternatif seperti yang ada dalam solusi ini atau secara manual menggunakan iterator.


0

Sebagai solusi cepat dan kotor yang memanfaatkan infrastruktur yang ada, Anda dapat membungkus Anda uglyPrintedMapmenjadi java.util.HashMap, lalu gunakan toString().

uglyPrintedMap.toString(); // ugly
System.out.println( uglyPrintedMap ); // prints in an ugly manner

new HashMap<Object, Object>(jobDataMap).toString(); // pretty
System.out.println( new HashMap<Object, Object>(uglyPrintedMap) ); // prints in a pretty manner

0

Tidak menjawab pertanyaan dengan tepat, tetapi @ToString penjelasan Lombodok patut disebutkan . Jika Anda membubuhi keterangan dengan @ToStringyang key / valuekelas, kemudian melakukanSystem.out.println(map) akan sesuatu yang berarti.

Ini juga bekerja sangat baik dengan maps-of-maps, misalnya: Map<MyKeyClass, Map<String, MyValueClass>>akan dicetak sebagai

{MyKeyClass(properties...)={string1=MyValuesClass(properties...), string2=MyValuesCalss(properties...),..}, ... }


0

Sejak java 8 ada cara mudah untuk melakukannya dengan Lambda:

yourMap.keySet().forEach(key -> {
    Object obj = yourMap.get(key);
    System.out.println( obj);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.