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.

space_monkey
sumber
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.

adarshr
sumber
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())
Arkadiusz Cieśliński
sumber
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));
Mark Wigmans
sumber
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>
tbraun
sumber
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)

Thamme Gowda
sumber
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}
AlikElzin-kilaka
sumber
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);
Nikita Koksharov
sumber
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 "";
    }
    
MattG
sumber
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 :-)

parasietje
sumber
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

Cratylus
sumber
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);
}
batu333
sumber
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.

pengguna2171669
sumber
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.

Tuan
sumber
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
Abdull
sumber
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...),..}, ... }

pengguna1485864
sumber
0

Sejak java 8 ada cara mudah untuk melakukannya dengan Lambda:

yourMap.keySet().forEach(key -> {
    Object obj = yourMap.get(key);
    System.out.println( obj);
}
Tomasz Stępnik
sumber