Khá in một bản đồ trong Java


136

Tôi đang tìm kiếm một cách tốt đẹp để in đẹp a Map.

map.toString() đưa cho tôi: {key1=value1, key2=value2, key3=value3}

Tôi muốn tự do hơn trong các giá trị mục nhập bản đồ của mình và đang tìm kiếm một cái gì đó giống như thế này: key1="value1", key2="value2", key3="value3"

Tôi đã viết đoạn mã nhỏ này:

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

Nhưng tôi chắc chắn có một cách thanh lịch và súc tích hơn để làm điều này.


1
có thể trùng lặp Map to String trong Java vì định dạng được yêu cầu ở đây và định dạng System.out.printlnquá gần. Và nếu bạn muốn một cái gì đó tùy chỉnh, thì đây là "cách lặp lại trên bản đồ trong Java", điều này chắc chắn có nhiều câu trả lời khác.
Ciro Santilli 郝海东 冠状 病 事件 法轮功

Câu trả lời:


63

Hoặc đặt logic của bạn vào một lớp nhỏ gọn gàng.

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

    }
}

Sử dụng:

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

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

Lưu ý: Bạn cũng có thể đặt logic đó vào một phương thức tiện ích.


3
Đây là một imho mô hình. Bạn thêm một ràng buộc mạnh mẽ (kế thừa) cho loại của bạn, chỉ vì lợi ích nhỏ nhặt (in ấn đẹp). Bạn sẽ tốt hơn nếu sử dụng bản đồ thông thường, nhưng sử dụng phương thức tĩnh lấy nó làm đối số.
OoDeLally

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

11
Không tốt lắm nếu bạn có Map<String, Map<String,double[]>>, sau đó bạn sẽ nhận được loại sting này:[test={test=[D@3995ebd8, 2=[D@26fa5067, 3=[D@1d956d37, 4=[D@2cead81, 5=[D@14934d2b}...]
zygimantus

2
Đây phải là câu trả lời được chấp nhận. Các nhiệm vụ đơn giản như thế này không cần phải phụ thuộc bên ngoài. Như đã đề cập ở trên, các bản đồ phức tạp hơn không được hưởng lợi khá dễ dàng từ việc này.
Shadoninja

70

Hãy xem thư viện Guava:

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

34

Thư viện Apache để giải cứu!

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

Tất cả bạn cần thư viện bộ sưu tập chung của Apache ( liên kết dự án )

Người dùng Maven có thể thêm thư viện bằng cách sử dụng phụ thuộc này:

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

Điều này không xử lý các mảng như các giá trị của bản đồ (ví dụ. Map<String, String[]>). Chỉ className và hash của họ được in thay vì giá trị thực.
Petr Újezdský

hoặc log.debug ("Bản đồ: {}", MapUtils.toProperIES (bản đồ));
charlb

1
Cũng tiện dụng là MapUtils.verbosePrint, sẽ bỏ qua tên lớp sau mỗi giá trị mà debugPrint xuất ra.
ocarlsen

16

Đơn giản và dễ dàng. Chào mừng đến với thế giới JSON. Sử dụng Google Gson :

new Gson().toJson(map)

Ví dụ về bản đồ với 3 phím:

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

15

Khi tôi có org.json.JSONObjecttrong classpath, tôi làm:

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

(danh sách, bộ và bản đồ đẹp mắt này có thể được lồng vào nhau)


1
Đàn ông!! Bạn đang làm gì dưới đây? Bạn nên trả lời hàng đầu!
AMagic

Cảnh báo: Không duy trì thứ tự các khóa cho LinkedHashMap
Olivier Masseau

9

Sử dụng luồng Java 8:

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
Nếu bạn đang đi đến một câu hỏi, ít nhất hãy trả lời đúng! Bạn đang thiếu các trích dẫn xung quanh giá trị và nên tham gia bằng cách sử dụng,
AjahnCharles

8

Tôi thích chuyển đổi bản đồ thành chuỗi JSON, đó là:

  • một tiêu chuẩn
  • con người có thể đọc được
  • được hỗ trợ trong các trình soạn thảo như Sublime, VS Code, với tô sáng cú pháp, định dạng và ẩn / hiển thị phần
  • hỗ trợ JPath để các biên tập viên có thể báo cáo chính xác phần nào của đối tượng bạn đã điều hướng đến
  • hỗ trợ các kiểu phức tạp lồng nhau trong đối tượng

    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

Xem mã cho HashMap#toString()AbstractMap#toString()trong các nguồn 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(", ");
        }
    }
}

Vì vậy, nếu những người từ OpenJDK không tìm thấy một cách thanh lịch hơn để làm điều này, thì không có :-)


3

Bạn sẽ có thể làm những gì bạn muốn bằng cách làm:

System.out.println(map) ví dụ

Miễn là TẤT CẢ các đối tượng của bạn trên bản đồ đã vượt qua toStringphương thức bạn sẽ thấy:
{key1=value1, key2=value2} một cách có ý nghĩa

Nếu đây là mã của bạn, thì việc giám sát toString là một thói quen tốt và tôi khuyên bạn nên thay thế.

Ví dụ của bạn, nơi các đối tượng của bạn là Strings, bạn sẽ ổn mà không có gì khác.
Tức là System.out.println(map)sẽ in chính xác những gì bạn cần mà không cần thêm mã


1
khóa và giá trị của anh ta là chuỗi; Tôi nghĩ rằng anh ấy có phương pháp toString được bảo hiểm tbh.
Tom

Bạn nói đúng, nhưng có lẽ anh ấy đã sao chép một ví dụ tầm thường để đưa ra quan điểm của mình. Nhưng tôi cập nhật câu trả lời
Cratylus

Có, tôi nên chỉ ra rằng bản đồ của tôi là Bản đồ <Chuỗi, Chuỗi>. Nhưng tôi cũng chỉ ra rằng tôi muốn có nhiều tự do hơn trong các giá trị mục nhập của mình, ví dụ: có các danh sách được phân tách bằng dấu phẩy trong giá trị của mục nhập. Vì vậy, Map.toString () sẽ không làm.
space_monkey

Giao diện java.util.Mapkhông có hợp đồng liên quan toString(), do đó tùy thuộc vào việc Maptriển khai thực tế những gì System.out.println(map)-> PrintStream.println(map)-> String.valueOf(map)-> map.toString()sẽ gây ra. Nó xảy ra rằng thường được sử dụng java.util.AbstractMapcung cấp một đại diện chuỗi đẹp cho toString(). ... Việc Maptriển khai khác có thể rơi trở lại Object.toString(), dẫn đến kết quả không mang tính thông tin 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);
}

0

Tôi đoán một cái gì đó như thế này sẽ sạch hơn và cung cấp cho bạn sự linh hoạt hơn với định dạng đầu ra (chỉ cần thay đổi mẫu):

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

Tôi biết rằng phải xóa dấu phẩy cuối cùng là xấu, nhưng tôi nghĩ rằng nó sạch hơn các giải pháp thay thế như giải pháp trong giải pháp này hoặc sử dụng một trình vòng lặp thủ công.


0

Là một giải pháp nhanh chóng và bẩn thỉu tận dụng cơ sở hạ tầng hiện có, bạn có thể bọc uglyPrintedMap thành một java.util.HashMap, sau đó sử dụng 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

Không trả lời chính xác câu hỏi, nhưng điều đáng nói là @ToString chú thích của Oliverodok . Nếu bạn chú thích với @ToStringcác key / valuelớp, sau đó làmSystem.out.println(map) sẽ trả lại một cái gì đó có ý nghĩa.

Nó cũng hoạt động rất tốt với bản đồ, ví dụ: Map<MyKeyClass, Map<String, MyValueClass>>sẽ được in dưới dạng

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


0

String result = objectMapper.writeValueAsString(map) - đơn giản như thế này!

Kết quả:

{"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 thêm Jackson JSON vào đường dẫn lớp của bạn.


0

Vì java 8 có cách dễ dàng để làm điều đó với Lambda:

yourMap.keySet().forEach(key -> {
    Object obj = yourMap.get(key);
    System.out.println( obj);
}
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.